Merge "Do not constrain width/height of child windows at layout." into nyc-dev
diff --git a/Android.mk b/Android.mk
index 024b2fd..1469c2c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -251,10 +251,13 @@
 	core/java/android/print/IPrintDocumentAdapterObserver.aidl \
 	core/java/android/print/IPrintJobStateChangeListener.aidl \
 	core/java/android/print/IPrintServicesChangeListener.aidl \
+	core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl \
 	core/java/android/print/IPrintManager.aidl \
 	core/java/android/print/IPrintSpooler.aidl \
 	core/java/android/print/IPrintSpoolerCallbacks.aidl \
 	core/java/android/print/IPrintSpoolerClient.aidl \
+	core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl \
+	core/java/android/printservice/recommendation/IRecommendationService.aidl \
 	core/java/android/print/IWriteResultCallback.aidl \
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
@@ -565,6 +568,7 @@
 	frameworks/base/core/java/android/print/PrintJobInfo.aidl \
 	frameworks/base/core/java/android/print/PrinterInfo.aidl \
 	frameworks/base/core/java/android/print/PrintJobId.aidl \
+	frameworks/base/core/java/android/printservice/recommendation/RecommendationInfo.aidl \
 	frameworks/base/core/java/android/hardware/usb/UsbDevice.aidl \
 	frameworks/base/core/java/android/hardware/usb/UsbInterface.aidl \
 	frameworks/base/core/java/android/hardware/usb/UsbEndpoint.aidl \
diff --git a/api/current.txt b/api/current.txt
index 298f6c4..051ad92 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -71,6 +71,7 @@
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -3425,7 +3426,7 @@
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     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 enterPictureInPicture();
+    method public void enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3465,15 +3466,16 @@
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
     method public boolean hasWindowFocus();
-    method public boolean inMultiWindow();
-    method public boolean inPictureInPicture();
     method public void invalidateOptionsMenu();
     method public boolean isChangingConfigurations();
     method public final boolean isChild();
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isInMultiWindowMode();
+    method public boolean isInPictureInPictureMode();
     method public boolean isLocalVoiceInteractionSupported();
+    method public boolean isOverlayWithDecorCaptionEnabled();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3520,7 +3522,7 @@
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
@@ -3528,7 +3530,7 @@
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method protected void onPostCreate(android.os.Bundle);
     method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
@@ -3566,7 +3568,6 @@
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
-    method public void overlayWithDecorCaption(boolean);
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
@@ -3595,6 +3596,7 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
+    method public void setOverlayWithDecorCaptionEnabled(boolean);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4437,11 +4439,11 @@
     method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
     method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method public void onPrepareOptionsMenu(android.view.Menu);
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method public void onResume();
@@ -4522,11 +4524,11 @@
     method public void dispatchDestroy();
     method public void dispatchDestroyView();
     method public void dispatchLowMemory();
-    method public void dispatchMultiWindowChanged(boolean);
+    method public void dispatchMultiWindowModeChanged(boolean);
     method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
     method public void dispatchOptionsMenuClosed(android.view.Menu);
     method public void dispatchPause();
-    method public void dispatchPictureInPictureChanged(boolean);
+    method public void dispatchPictureInPictureModeChanged(boolean);
     method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
     method public void dispatchResume();
     method public void dispatchStart();
@@ -5754,8 +5756,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
-    field public static final int FLAG_SET_LOCK = 2; // 0x2
-    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+    field public static final int FLAG_LOCK = 2; // 0x2
+    field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5863,7 +5865,6 @@
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.String getOrganizationName(android.content.ComponentName);
-    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5900,7 +5901,9 @@
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
@@ -8224,8 +8227,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -9916,6 +9917,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
     field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -9993,7 +9995,7 @@
     field public java.lang.String permission;
   }
 
-  public class ShortcutInfo implements android.os.Parcelable {
+  public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getActivityComponent();
     method public android.os.PersistableBundle getExtras();
@@ -13504,6 +13506,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getId();
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
@@ -13513,9 +13516,10 @@
     method public float getResolution();
     method public java.lang.String getStringType();
     method public int getType();
-    method public java.util.UUID getUuid();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isAdditionalInfoSupported();
+    method public boolean isDynamicSensor();
     method public boolean isWakeUpSensor();
     field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13634,8 +13638,9 @@
     method public static void getRotationMatrixFromVector(float[], float[]);
     method public java.util.List<android.hardware.Sensor> getSensorList(int);
     method public deprecated int getSensors();
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+    method public boolean isDynamicSensorDiscoverySupported();
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13644,7 +13649,7 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
     method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13709,8 +13714,8 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorConnectionCallback {
-    ctor public SensorManager.DynamicSensorConnectionCallback();
+  public static abstract class SensorManager.DynamicSensorCallback {
+    ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
   }
@@ -14835,7 +14840,6 @@
 
   public static abstract interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
@@ -14844,7 +14848,6 @@
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
-    field public static final int COUNT = 18; // 0x12
     field public static final int FINAL = 4; // 0x4
     field public static final int FONT = 5; // 0x5
     field public static final int FRACTION = 6; // 0x6
@@ -14864,7 +14867,6 @@
 
   public static abstract interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
-    field public static final int COUNT = 6; // 0x6
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
     field public static final int NARROW = 4; // 0x4
@@ -14874,7 +14876,6 @@
 
   public static abstract interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
-    field public static final int COUNT = 13; // 0xd
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
     field public static final int L = 4; // 0x4
@@ -14890,7 +14891,6 @@
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -14906,7 +14906,6 @@
     field public static final int BEH = 4; // 0x4
     field public static final int BETH = 5; // 0x5
     field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
-    field public static final int COUNT = 86; // 0x56
     field public static final int DAL = 6; // 0x6
     field public static final int DALATH_RISH = 7; // 0x7
     field public static final int E = 8; // 0x8
@@ -14991,7 +14990,6 @@
   }
 
   public static abstract interface UCharacter.JoiningType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -15014,7 +15012,6 @@
     field public static final int COMPLEX_CONTEXT = 24; // 0x18
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
-    field public static final int COUNT = 40; // 0x28
     field public static final int EXCLAMATION = 11; // 0xb
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
@@ -15046,7 +15043,6 @@
   }
 
   public static abstract interface UCharacter.NumericType {
-    field public static final int COUNT = 4; // 0x4
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
@@ -15056,7 +15052,6 @@
   public static abstract interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 15; // 0xf
     field public static final int CR = 11; // 0xb
     field public static final int EXTEND = 12; // 0xc
     field public static final int FORMAT = 3; // 0x3
@@ -15199,7 +15194,6 @@
     field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
     field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
     field public static final int COPTIC_ID = 132; // 0x84
-    field public static final int COUNT = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
     field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
     field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -15613,7 +15607,6 @@
 
   public static abstract interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
-    field public static final int COUNT = 17; // 0x11
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
@@ -15644,7 +15637,6 @@
   }
 
   public static abstract interface UCharacterEnums.ECharacterCategory {
-    field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -15684,7 +15676,6 @@
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
-    field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
     field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
     field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
     field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -15737,7 +15728,6 @@
     field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
     field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
     field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
-    field public static final int BINARY_LIMIT = 57; // 0x39
     field public static final int BINARY_START = 0; // 0x0
     field public static final int BLOCK = 4097; // 0x1001
     field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -15756,7 +15746,6 @@
     field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
     field public static final int DEPRECATED = 6; // 0x6
     field public static final int DIACRITIC = 7; // 0x7
-    field public static final int DOUBLE_LIMIT = 12289; // 0x3001
     field public static final int DOUBLE_START = 12288; // 0x3000
     field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
     field public static final int EXTENDER = 8; // 0x8
@@ -15775,7 +15764,6 @@
     field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
     field public static final int ID_CONTINUE = 15; // 0xf
     field public static final int ID_START = 16; // 0x10
-    field public static final int INT_LIMIT = 4118; // 0x1016
     field public static final int INT_START = 4096; // 0x1000
     field public static final int JOINING_GROUP = 4102; // 0x1006
     field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -15785,7 +15773,6 @@
     field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
     field public static final int LOWERCASE = 22; // 0x16
     field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
-    field public static final int MASK_LIMIT = 8193; // 0x2001
     field public static final int MASK_START = 8192; // 0x2000
     field public static final int MATH = 23; // 0x17
     field public static final int NAME = 16389; // 0x4005
@@ -15800,7 +15787,6 @@
     field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
     field public static final int NUMERIC_TYPE = 4105; // 0x1009
     field public static final int NUMERIC_VALUE = 12288; // 0x3000
-    field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
     field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
     field public static final int PATTERN_SYNTAX = 42; // 0x2a
     field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -15820,7 +15806,6 @@
     field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
     field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
     field public static final int SOFT_DOTTED = 27; // 0x1b
-    field public static final int STRING_LIMIT = 16398; // 0x400e
     field public static final int STRING_START = 16384; // 0x4000
     field public static final int S_TERM = 35; // 0x23
     field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -15837,7 +15822,6 @@
   }
 
   public static abstract interface UProperty.NameChoice {
-    field public static final int COUNT = 2; // 0x2
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -15882,7 +15866,6 @@
     field public static final int CHAM = 66; // 0x42
     field public static final int CHEROKEE = 6; // 0x6
     field public static final int CIRTH = 67; // 0x43
-    field public static final int CODE_LIMIT = 167; // 0xa7
     field public static final int COMMON = 0; // 0x0
     field public static final int COPTIC = 7; // 0x7
     field public static final int CUNEIFORM = 101; // 0x65
@@ -16277,7 +16260,6 @@
 
   public final class CollationKey implements java.lang.Comparable {
     ctor public CollationKey(java.lang.String, byte[]);
-    ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
@@ -16287,7 +16269,6 @@
   }
 
   public static final class CollationKey.BoundMode {
-    field public static final int COUNT = 3; // 0x3
     field public static final int LOWER = 0; // 0x0
     field public static final int UPPER = 1; // 0x1
     field public static final int UPPER_LONG = 2; // 0x2
@@ -16319,7 +16300,6 @@
     method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
     method public static final java.lang.String[] getKeywords();
     method public int getMaxVariable();
-    method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int[] getReorderCodes();
     method public int getStrength();
     method public android.icu.text.UnicodeSet getTailoredSet();
@@ -16359,7 +16339,6 @@
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
     field public static final int FIRST = 4096; // 0x1000
-    field public static final int LIMIT = 4101; // 0x1005
     field public static final int NONE = 103; // 0x67
     field public static final int OTHERS = 103; // 0x67
     field public static final int PUNCTUATION = 4097; // 0x1001
@@ -16472,7 +16451,6 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
-    field public static final int FIELD_COUNT = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16716,7 +16694,6 @@
     field public static final int MONTH = 3; // 0x3
     field public static final int QUARTER = 2; // 0x2
     field public static final int SECOND = 13; // 0xd
-    field public static final int TYPE_LIMIT = 16; // 0x10
     field public static final int WEEKDAY = 6; // 0x6
     field public static final int WEEK_OF_MONTH = 5; // 0x5
     field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -17347,14 +17324,6 @@
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
-  public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
-    ctor public RawCollationKey();
-    ctor public RawCollationKey(int);
-    ctor public RawCollationKey(byte[]);
-    ctor public RawCollationKey(byte[], int);
-    method public int compareTo(android.icu.text.RawCollationKey);
-  }
-
   public final class RelativeDateTimeFormatter {
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -17438,7 +17407,6 @@
     method public android.icu.text.CollationKey getCollationKey(java.lang.String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public java.lang.String getRules();
     method public java.lang.String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
@@ -17933,19 +17901,6 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public class ByteArrayWrapper implements java.lang.Comparable {
-    ctor public ByteArrayWrapper();
-    ctor public ByteArrayWrapper(byte[], int);
-    ctor public ByteArrayWrapper(java.nio.ByteBuffer);
-    method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
-    method public int compareTo(android.icu.util.ByteArrayWrapper);
-    method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
-    method public final byte[] releaseBytes();
-    method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
-    field public byte[] bytes;
-    field public int size;
-  }
-
    abstract class CECalendar extends android.icu.util.Calendar {
     ctor protected CECalendar();
     ctor protected CECalendar(android.icu.util.TimeZone);
@@ -19857,7 +19812,7 @@
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+    method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20134,6 +20089,7 @@
     method public int getAttributeInt(java.lang.String, int);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
+    method public long[] getThumbnailRange();
     method public boolean hasThumbnail();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(java.lang.String, java.lang.String);
@@ -20146,7 +20102,7 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final java.lang.String TAG_APERTURE = "FNumber";
+    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
     field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
     field public static final java.lang.String TAG_ARTIST = "Artist";
     field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -20217,7 +20173,7 @@
     field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
     field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
     field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
-    field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
     field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
     field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
     field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -20625,12 +20581,13 @@
     field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
     field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
     field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
-    field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
-    field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
-    field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
-    field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
-    field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
-    field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+    field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+    field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+    field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+    field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+    field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+    field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+    field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
     field public static final int H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -28757,6 +28714,7 @@
     field public static final int TEMPERATURE_CURRENT = 0; // 0x0
     field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
     field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+    field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
     field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
@@ -29116,6 +29074,7 @@
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
     method public deprecated boolean isScreenOn();
+    method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
@@ -29129,6 +29088,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
@@ -29485,7 +29445,7 @@
     method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
   }
 
-  public class TimerStat implements android.os.Parcelable {
+  public final class TimerStat implements android.os.Parcelable {
     ctor public TimerStat();
     ctor public TimerStat(int, long);
     ctor public TimerStat(android.os.Parcel);
@@ -31929,6 +31889,7 @@
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
     field public static final java.lang.String EXTRA_LOADING = "loading";
+    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
     field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
   }
@@ -36770,6 +36731,7 @@
     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 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_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -37958,8 +37920,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -44301,6 +44261,7 @@
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
     method public int getChildCount();
@@ -44308,6 +44269,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+    method public java.lang.CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -44648,6 +44610,7 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -44815,6 +44778,7 @@
   public abstract interface InputConnection {
     method public abstract boolean beginBatchEdit();
     method public abstract boolean clearMetaKeyStates(int);
+    method public abstract void closeConnection();
     method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -44847,6 +44811,7 @@
     ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -49307,9 +49272,7 @@
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
     ctor public FilePermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -50048,6 +50011,7 @@
     method public static int compare(boolean, boolean);
     method public int compareTo(java.lang.Boolean);
     method public static boolean getBoolean(java.lang.String);
+    method public static int hashCode(boolean);
     method public static boolean parseBoolean(java.lang.String);
     method public static java.lang.String toString(boolean);
     method public static java.lang.Boolean valueOf(boolean);
@@ -50065,6 +50029,7 @@
     method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50073,6 +50038,7 @@
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
@@ -50110,6 +50076,7 @@
     method public static int getNumericValue(int);
     method public static int getType(char);
     method public static int getType(int);
+    method public static int hashCode(char);
     method public static char highSurrogate(int);
     method public static boolean isAlphabetic(int);
     method public static boolean isBmpCodePoint(int);
@@ -50170,6 +50137,7 @@
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
     method public static java.lang.Character valueOf(char);
+    field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
     field public static final byte CONTROL = 15; // 0xf
@@ -50796,6 +50764,7 @@
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
     method public float floatValue();
+    method public static int hashCode(float);
     method public static float intBitsToFloat(int);
     method public int intValue();
     method public static boolean isFinite(float);
@@ -50804,11 +50773,15 @@
     method public static boolean isNaN(float);
     method public boolean isNaN();
     method public long longValue();
+    method public static float max(float, float);
+    method public static float min(float, float);
     method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float sum(float, float);
     method public static java.lang.String toHexString(float);
     method public static java.lang.String toString(float);
     method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Float valueOf(float);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
     field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -50988,6 +50961,7 @@
     method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(long);
+    field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
@@ -51291,6 +51265,7 @@
     method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
     method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51300,6 +51275,7 @@
     method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(short);
+    field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
@@ -52823,9 +52799,7 @@
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
     ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53907,9 +53881,7 @@
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
     ctor public AllPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53923,9 +53895,7 @@
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
     ctor public BasicPermission(java.lang.String);
     ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54303,10 +54273,8 @@
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getActions();
     method public final java.lang.String getName();
-    method public abstract int hashCode();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -54564,13 +54532,11 @@
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
     ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
     method public java.lang.String getUnresolvedName();
     method public java.lang.String getUnresolvedType();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54628,8 +54594,6 @@
   }
 
   public abstract interface Permission {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String toString();
   }
 
 }
@@ -63938,11 +63902,9 @@
 
   public final class PrivateCredentialPermission extends java.security.Permission {
     ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getCredentialClass();
     method public java.lang.String[][] getPrincipals();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
diff --git a/api/removed.txt b/api/removed.txt
index 86085c8..3f16bca 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -94,6 +94,10 @@
 
 package android.media.tv {
 
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
   public class TvView extends android.view.ViewGroup {
     method public void requestUnblockContent(android.media.tv.TvContentRating);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 0651c61..8834461 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -42,6 +42,7 @@
     field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
+    field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
@@ -102,6 +103,7 @@
     field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
     field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
@@ -3540,7 +3542,7 @@
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     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 enterPictureInPicture();
+    method public void enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3580,8 +3582,6 @@
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
     method public boolean hasWindowFocus();
-    method public boolean inMultiWindow();
-    method public boolean inPictureInPicture();
     method public void invalidateOptionsMenu();
     method public boolean isBackgroundVisibleBehind();
     method public boolean isChangingConfigurations();
@@ -3589,7 +3589,10 @@
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isInMultiWindowMode();
+    method public boolean isInPictureInPictureMode();
     method public boolean isLocalVoiceInteractionSupported();
+    method public boolean isOverlayWithDecorCaptionEnabled();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3637,7 +3640,7 @@
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
@@ -3645,7 +3648,7 @@
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method protected void onPostCreate(android.os.Bundle);
     method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
@@ -3683,7 +3686,6 @@
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
-    method public void overlayWithDecorCaption(boolean);
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
@@ -3712,6 +3714,7 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
+    method public void setOverlayWithDecorCaptionEnabled(boolean);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4569,11 +4572,11 @@
     method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
     method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method public void onPrepareOptionsMenu(android.view.Menu);
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method public void onResume();
@@ -4654,11 +4657,11 @@
     method public void dispatchDestroy();
     method public void dispatchDestroyView();
     method public void dispatchLowMemory();
-    method public void dispatchMultiWindowChanged(boolean);
+    method public void dispatchMultiWindowModeChanged(boolean);
     method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
     method public void dispatchOptionsMenuClosed(android.view.Menu);
     method public void dispatchPause();
-    method public void dispatchPictureInPictureChanged(boolean);
+    method public void dispatchPictureInPictureModeChanged(boolean);
     method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
     method public void dispatchResume();
     method public void dispatchStart();
@@ -5891,8 +5894,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
-    field public static final int FLAG_SET_LOCK = 2; // 0x2
-    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+    field public static final int FLAG_LOCK = 2; // 0x2
+    field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -6004,7 +6007,6 @@
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.String getOrganizationName(android.content.ComponentName);
-    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -6046,7 +6048,9 @@
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
@@ -8534,8 +8538,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -10314,6 +10316,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
     field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -10391,7 +10394,7 @@
     field public java.lang.String permission;
   }
 
-  public class ShortcutInfo implements android.os.Parcelable {
+  public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getActivityComponent();
     method public android.os.PersistableBundle getExtras();
@@ -13902,6 +13905,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getId();
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
@@ -13914,7 +13918,9 @@
     method public java.util.UUID getUuid();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isAdditionalInfoSupported();
     method public boolean isDataInjectionSupported();
+    method public boolean isDynamicSensor();
     method public boolean isWakeUpSensor();
     field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -14039,8 +14045,9 @@
     method public deprecated int getSensors();
     method public boolean initDataInjection(boolean);
     method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+    method public boolean isDynamicSensorDiscoverySupported();
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -14049,7 +14056,7 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
     method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -14114,8 +14121,8 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorConnectionCallback {
-    ctor public SensorManager.DynamicSensorConnectionCallback();
+  public static abstract class SensorManager.DynamicSensorCallback {
+    ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
   }
@@ -15264,6 +15271,7 @@
     ctor public ContextHubInfo();
     method public int describeContents();
     method public int getId();
+    method public int getMaxPacketLengthBytes();
     method public android.hardware.location.MemoryRegion[] getMemoryRegions();
     method public java.lang.String getName();
     method public float getPeakMips();
@@ -15291,10 +15299,6 @@
     method public int sendMessage(int, int, android.hardware.location.ContextHubMessage);
     method public int unloadNanoApp(int);
     method public int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
-    field public static final int ANY_HUB = -1; // 0xffffffff
-    field public static final int MSG_DATA_SEND = 3; // 0x3
-    field public static final int MSG_LOAD_NANO_APP = 1; // 0x1
-    field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
   }
 
   public static abstract class ContextHubManager.Callback {
@@ -15488,7 +15492,7 @@
   public class NanoAppInstanceInfo {
     ctor public NanoAppInstanceInfo();
     method public int describeContents();
-    method public int getAppId();
+    method public long getAppId();
     method public int getAppVersion();
     method public int getContexthubId();
     method public int getHandle();
@@ -15499,17 +15503,6 @@
     method public int getNeededWriteMemBytes();
     method public int[] getOutputEvents();
     method public java.lang.String getPublisher();
-    method public void setAppId(int);
-    method public void setAppVersion(int);
-    method public void setContexthubId(int);
-    method public void setHandle(int);
-    method public void setName(java.lang.String);
-    method public void setNeededExecMemBytes(int);
-    method public void setNeededReadMemBytes(int);
-    method public void setNeededSensors(int[]);
-    method public void setNeededWriteMemBytes(int);
-    method public void setOutputEvents(int[]);
-    method public void setPublisher(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
   }
@@ -16007,7 +16000,6 @@
 
   public static abstract interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
@@ -16016,7 +16008,6 @@
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
-    field public static final int COUNT = 18; // 0x12
     field public static final int FINAL = 4; // 0x4
     field public static final int FONT = 5; // 0x5
     field public static final int FRACTION = 6; // 0x6
@@ -16036,7 +16027,6 @@
 
   public static abstract interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
-    field public static final int COUNT = 6; // 0x6
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
     field public static final int NARROW = 4; // 0x4
@@ -16046,7 +16036,6 @@
 
   public static abstract interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
-    field public static final int COUNT = 13; // 0xd
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
     field public static final int L = 4; // 0x4
@@ -16062,7 +16051,6 @@
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -16078,7 +16066,6 @@
     field public static final int BEH = 4; // 0x4
     field public static final int BETH = 5; // 0x5
     field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
-    field public static final int COUNT = 86; // 0x56
     field public static final int DAL = 6; // 0x6
     field public static final int DALATH_RISH = 7; // 0x7
     field public static final int E = 8; // 0x8
@@ -16163,7 +16150,6 @@
   }
 
   public static abstract interface UCharacter.JoiningType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -16186,7 +16172,6 @@
     field public static final int COMPLEX_CONTEXT = 24; // 0x18
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
-    field public static final int COUNT = 40; // 0x28
     field public static final int EXCLAMATION = 11; // 0xb
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
@@ -16218,7 +16203,6 @@
   }
 
   public static abstract interface UCharacter.NumericType {
-    field public static final int COUNT = 4; // 0x4
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
@@ -16228,7 +16212,6 @@
   public static abstract interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 15; // 0xf
     field public static final int CR = 11; // 0xb
     field public static final int EXTEND = 12; // 0xc
     field public static final int FORMAT = 3; // 0x3
@@ -16371,7 +16354,6 @@
     field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
     field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
     field public static final int COPTIC_ID = 132; // 0x84
-    field public static final int COUNT = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
     field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
     field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -16785,7 +16767,6 @@
 
   public static abstract interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
-    field public static final int COUNT = 17; // 0x11
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
@@ -16816,7 +16797,6 @@
   }
 
   public static abstract interface UCharacterEnums.ECharacterCategory {
-    field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -16856,7 +16836,6 @@
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
-    field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
     field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
     field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
     field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -16909,7 +16888,6 @@
     field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
     field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
     field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
-    field public static final int BINARY_LIMIT = 57; // 0x39
     field public static final int BINARY_START = 0; // 0x0
     field public static final int BLOCK = 4097; // 0x1001
     field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -16928,7 +16906,6 @@
     field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
     field public static final int DEPRECATED = 6; // 0x6
     field public static final int DIACRITIC = 7; // 0x7
-    field public static final int DOUBLE_LIMIT = 12289; // 0x3001
     field public static final int DOUBLE_START = 12288; // 0x3000
     field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
     field public static final int EXTENDER = 8; // 0x8
@@ -16947,7 +16924,6 @@
     field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
     field public static final int ID_CONTINUE = 15; // 0xf
     field public static final int ID_START = 16; // 0x10
-    field public static final int INT_LIMIT = 4118; // 0x1016
     field public static final int INT_START = 4096; // 0x1000
     field public static final int JOINING_GROUP = 4102; // 0x1006
     field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -16957,7 +16933,6 @@
     field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
     field public static final int LOWERCASE = 22; // 0x16
     field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
-    field public static final int MASK_LIMIT = 8193; // 0x2001
     field public static final int MASK_START = 8192; // 0x2000
     field public static final int MATH = 23; // 0x17
     field public static final int NAME = 16389; // 0x4005
@@ -16972,7 +16947,6 @@
     field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
     field public static final int NUMERIC_TYPE = 4105; // 0x1009
     field public static final int NUMERIC_VALUE = 12288; // 0x3000
-    field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
     field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
     field public static final int PATTERN_SYNTAX = 42; // 0x2a
     field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -16992,7 +16966,6 @@
     field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
     field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
     field public static final int SOFT_DOTTED = 27; // 0x1b
-    field public static final int STRING_LIMIT = 16398; // 0x400e
     field public static final int STRING_START = 16384; // 0x4000
     field public static final int S_TERM = 35; // 0x23
     field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -17009,7 +16982,6 @@
   }
 
   public static abstract interface UProperty.NameChoice {
-    field public static final int COUNT = 2; // 0x2
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -17054,7 +17026,6 @@
     field public static final int CHAM = 66; // 0x42
     field public static final int CHEROKEE = 6; // 0x6
     field public static final int CIRTH = 67; // 0x43
-    field public static final int CODE_LIMIT = 167; // 0xa7
     field public static final int COMMON = 0; // 0x0
     field public static final int COPTIC = 7; // 0x7
     field public static final int CUNEIFORM = 101; // 0x65
@@ -17449,7 +17420,6 @@
 
   public final class CollationKey implements java.lang.Comparable {
     ctor public CollationKey(java.lang.String, byte[]);
-    ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
@@ -17459,7 +17429,6 @@
   }
 
   public static final class CollationKey.BoundMode {
-    field public static final int COUNT = 3; // 0x3
     field public static final int LOWER = 0; // 0x0
     field public static final int UPPER = 1; // 0x1
     field public static final int UPPER_LONG = 2; // 0x2
@@ -17491,7 +17460,6 @@
     method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
     method public static final java.lang.String[] getKeywords();
     method public int getMaxVariable();
-    method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int[] getReorderCodes();
     method public int getStrength();
     method public android.icu.text.UnicodeSet getTailoredSet();
@@ -17531,7 +17499,6 @@
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
     field public static final int FIRST = 4096; // 0x1000
-    field public static final int LIMIT = 4101; // 0x1005
     field public static final int NONE = 103; // 0x67
     field public static final int OTHERS = 103; // 0x67
     field public static final int PUNCTUATION = 4097; // 0x1001
@@ -17644,7 +17611,6 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
-    field public static final int FIELD_COUNT = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -17888,7 +17854,6 @@
     field public static final int MONTH = 3; // 0x3
     field public static final int QUARTER = 2; // 0x2
     field public static final int SECOND = 13; // 0xd
-    field public static final int TYPE_LIMIT = 16; // 0x10
     field public static final int WEEKDAY = 6; // 0x6
     field public static final int WEEK_OF_MONTH = 5; // 0x5
     field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -18519,14 +18484,6 @@
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
-  public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
-    ctor public RawCollationKey();
-    ctor public RawCollationKey(int);
-    ctor public RawCollationKey(byte[]);
-    ctor public RawCollationKey(byte[], int);
-    method public int compareTo(android.icu.text.RawCollationKey);
-  }
-
   public final class RelativeDateTimeFormatter {
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -18610,7 +18567,6 @@
     method public android.icu.text.CollationKey getCollationKey(java.lang.String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public java.lang.String getRules();
     method public java.lang.String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
@@ -19105,19 +19061,6 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public class ByteArrayWrapper implements java.lang.Comparable {
-    ctor public ByteArrayWrapper();
-    ctor public ByteArrayWrapper(byte[], int);
-    ctor public ByteArrayWrapper(java.nio.ByteBuffer);
-    method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
-    method public int compareTo(android.icu.util.ByteArrayWrapper);
-    method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
-    method public final byte[] releaseBytes();
-    method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
-    field public byte[] bytes;
-    field public int size;
-  }
-
    abstract class CECalendar extends android.icu.util.Calendar {
     ctor protected CECalendar();
     ctor protected CECalendar(android.icu.util.TimeZone);
@@ -21345,7 +21288,7 @@
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+    method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21625,6 +21568,7 @@
     method public int getAttributeInt(java.lang.String, int);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
+    method public long[] getThumbnailRange();
     method public boolean hasThumbnail();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(java.lang.String, java.lang.String);
@@ -21637,7 +21581,7 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final java.lang.String TAG_APERTURE = "FNumber";
+    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
     field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
     field public static final java.lang.String TAG_ARTIST = "Artist";
     field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -21708,7 +21652,7 @@
     field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
     field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
     field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
-    field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
     field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
     field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
     field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -22116,12 +22060,13 @@
     field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
     field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
     field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
-    field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
-    field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
-    field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
-    field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
-    field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
-    field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+    field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+    field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+    field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+    field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+    field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+    field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+    field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
     field public static final int H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -24673,6 +24618,7 @@
     method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
     method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
     method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
+    method public android.media.tv.TvInputInfo.Builder setLabel(java.lang.CharSequence);
     method public android.media.tv.TvInputInfo.Builder setLabel(int);
     method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24687,7 +24633,7 @@
   }
 
   public final class TvInputManager {
-    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputInfo, android.media.tv.TvInputManager.HardwareCallback);
     method public void addBlockedRating(android.media.tv.TvContentRating);
     method public boolean captureFrame(java.lang.String, android.view.Surface, android.media.tv.TvStreamConfig);
     method public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(java.lang.String);
@@ -31000,6 +30946,7 @@
     field public static final int TEMPERATURE_CURRENT = 0; // 0x0
     field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
     field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+    field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
     field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
@@ -31360,6 +31307,7 @@
     method public boolean isPowerSaveMode();
     method public boolean isScreenBrightnessBoosted();
     method public deprecated boolean isScreenOn();
+    method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
@@ -31375,6 +31323,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -31800,7 +31749,7 @@
     method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
   }
 
-  public class TimerStat implements android.os.Parcelable {
+  public final class TimerStat implements android.os.Parcelable {
     ctor public TimerStat();
     ctor public TimerStat(int, long);
     ctor public TimerStat(android.os.Parcel);
@@ -32700,6 +32649,29 @@
 
 }
 
+package android.printservice.recommendation {
+
+  public final class RecommendationInfo implements android.os.Parcelable {
+    ctor public RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, int, boolean);
+    method public int describeContents();
+    method public java.lang.CharSequence getName();
+    method public int getNumDiscoveredPrinters();
+    method public java.lang.CharSequence getPackageName();
+    method public boolean recommendsMultiVendorService();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.printservice.recommendation.RecommendationInfo> CREATOR;
+  }
+
+  public abstract class RecommendationService extends android.app.Service {
+    ctor public RecommendationService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onConnected();
+    method public abstract void onDisconnected();
+    method public final void updateRecommendations(java.util.List<android.printservice.recommendation.RecommendationInfo>);
+  }
+
+}
+
 package android.provider {
 
   public final class AlarmClock {
@@ -34276,6 +34248,7 @@
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
     field public static final java.lang.String EXTRA_LOADING = "loading";
+    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
     field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
   }
@@ -39434,6 +39407,7 @@
     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 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_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -40676,8 +40650,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -47032,6 +47004,7 @@
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
     method public int getChildCount();
@@ -47039,6 +47012,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+    method public java.lang.CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -47379,6 +47353,7 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -47546,6 +47521,7 @@
   public abstract interface InputConnection {
     method public abstract boolean beginBatchEdit();
     method public abstract boolean clearMetaKeyStates(int);
+    method public abstract void closeConnection();
     method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -47578,6 +47554,7 @@
     ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -48671,6 +48648,7 @@
     method public int getPackageId(android.content.res.Resources, java.lang.String);
     method public void invokeDrawGlFunctor(android.view.View, long, boolean);
     method public boolean isTraceTagEnabled();
+    method public java.lang.Runnable setDrawGlFunctionDetachedCallback(android.view.View, java.lang.Runnable);
     method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
   }
 
@@ -48876,6 +48854,24 @@
     method public abstract boolean shouldDelayChildPressedState();
   }
 
+  public final class WebViewProviderInfo implements android.os.Parcelable {
+    ctor public WebViewProviderInfo(java.lang.String, java.lang.String, boolean, boolean, java.lang.String[]);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.webkit.WebViewProviderInfo> CREATOR;
+    field public final boolean availableByDefault;
+    field public final java.lang.String description;
+    field public final boolean isFallback;
+    field public final java.lang.String packageName;
+    field public final java.lang.String[] signatures;
+  }
+
+  public final class WebViewUpdateService {
+    method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
+    method public static java.lang.String getCurrentWebViewPackageName();
+    method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+  }
+
 }
 
 package android.widget {
@@ -52373,9 +52369,7 @@
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
     ctor public FilePermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53114,6 +53108,7 @@
     method public static int compare(boolean, boolean);
     method public int compareTo(java.lang.Boolean);
     method public static boolean getBoolean(java.lang.String);
+    method public static int hashCode(boolean);
     method public static boolean parseBoolean(java.lang.String);
     method public static java.lang.String toString(boolean);
     method public static java.lang.Boolean valueOf(boolean);
@@ -53131,6 +53126,7 @@
     method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53139,6 +53135,7 @@
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
@@ -53176,6 +53173,7 @@
     method public static int getNumericValue(int);
     method public static int getType(char);
     method public static int getType(int);
+    method public static int hashCode(char);
     method public static char highSurrogate(int);
     method public static boolean isAlphabetic(int);
     method public static boolean isBmpCodePoint(int);
@@ -53236,6 +53234,7 @@
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
     method public static java.lang.Character valueOf(char);
+    field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
     field public static final byte CONTROL = 15; // 0xf
@@ -53862,6 +53861,7 @@
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
     method public float floatValue();
+    method public static int hashCode(float);
     method public static float intBitsToFloat(int);
     method public int intValue();
     method public static boolean isFinite(float);
@@ -53870,11 +53870,15 @@
     method public static boolean isNaN(float);
     method public boolean isNaN();
     method public long longValue();
+    method public static float max(float, float);
+    method public static float min(float, float);
     method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float sum(float, float);
     method public static java.lang.String toHexString(float);
     method public static java.lang.String toString(float);
     method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Float valueOf(float);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
     field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -54054,6 +54058,7 @@
     method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(long);
+    field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
@@ -54357,6 +54362,7 @@
     method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
     method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -54366,6 +54372,7 @@
     method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(short);
+    field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
@@ -55889,9 +55896,7 @@
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
     ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -56973,9 +56978,7 @@
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
     ctor public AllPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -56989,9 +56992,7 @@
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
     ctor public BasicPermission(java.lang.String);
     ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -57369,10 +57370,8 @@
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getActions();
     method public final java.lang.String getName();
-    method public abstract int hashCode();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -57630,13 +57629,11 @@
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
     ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
     method public java.lang.String getUnresolvedName();
     method public java.lang.String getUnresolvedType();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -57694,8 +57691,6 @@
   }
 
   public abstract interface Permission {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String toString();
   }
 
 }
@@ -67004,11 +66999,9 @@
 
   public final class PrivateCredentialPermission extends java.security.Permission {
     ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getCredentialClass();
     method public java.lang.String[][] getPrincipals();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
diff --git a/api/system-removed.txt b/api/system-removed.txt
index bc17627..03cf8b0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -92,6 +92,10 @@
 
 package android.media.tv {
 
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
   public class TvView extends android.view.ViewGroup {
     method public void requestUnblockContent(android.media.tv.TvContentRating);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 2a9f452..2165b32 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -71,6 +71,7 @@
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -3425,7 +3426,7 @@
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     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 enterPictureInPicture();
+    method public void enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3465,15 +3466,16 @@
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
     method public boolean hasWindowFocus();
-    method public boolean inMultiWindow();
-    method public boolean inPictureInPicture();
     method public void invalidateOptionsMenu();
     method public boolean isChangingConfigurations();
     method public final boolean isChild();
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isInMultiWindowMode();
+    method public boolean isInPictureInPictureMode();
     method public boolean isLocalVoiceInteractionSupported();
+    method public boolean isOverlayWithDecorCaptionEnabled();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3520,7 +3522,7 @@
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
@@ -3528,7 +3530,7 @@
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method protected void onPostCreate(android.os.Bundle);
     method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
@@ -3566,7 +3568,6 @@
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
-    method public void overlayWithDecorCaption(boolean);
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
@@ -3595,6 +3596,7 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
+    method public void setOverlayWithDecorCaptionEnabled(boolean);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4437,11 +4439,11 @@
     method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
     method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
     method public void onLowMemory();
-    method public void onMultiWindowChanged(boolean);
+    method public void onMultiWindowModeChanged(boolean);
     method public boolean onOptionsItemSelected(android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
     method public void onPause();
-    method public void onPictureInPictureChanged(boolean);
+    method public void onPictureInPictureModeChanged(boolean);
     method public void onPrepareOptionsMenu(android.view.Menu);
     method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
     method public void onResume();
@@ -4522,11 +4524,11 @@
     method public void dispatchDestroy();
     method public void dispatchDestroyView();
     method public void dispatchLowMemory();
-    method public void dispatchMultiWindowChanged(boolean);
+    method public void dispatchMultiWindowModeChanged(boolean);
     method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
     method public void dispatchOptionsMenuClosed(android.view.Menu);
     method public void dispatchPause();
-    method public void dispatchPictureInPictureChanged(boolean);
+    method public void dispatchPictureInPictureModeChanged(boolean);
     method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
     method public void dispatchResume();
     method public void dispatchStart();
@@ -5758,8 +5760,8 @@
     field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
     field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
     field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
-    field public static final int FLAG_SET_LOCK = 2; // 0x2
-    field public static final int FLAG_SET_SYSTEM = 1; // 0x1
+    field public static final int FLAG_LOCK = 2; // 0x2
+    field public static final int FLAG_SYSTEM = 1; // 0x1
     field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5867,7 +5869,6 @@
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
     method public java.lang.String getOrganizationName(android.content.ComponentName);
-    method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5904,7 +5905,9 @@
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isManagedProfile(android.content.ComponentName);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
+    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
@@ -8230,8 +8233,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -9926,6 +9927,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
     field public static final int PROTECTION_MASK_BASE = 15; // 0xf
@@ -10003,7 +10005,7 @@
     field public java.lang.String permission;
   }
 
-  public class ShortcutInfo implements android.os.Parcelable {
+  public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getActivityComponent();
     method public android.os.PersistableBundle getExtras();
@@ -13514,6 +13516,7 @@
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
+    method public int getId();
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
@@ -13523,9 +13526,10 @@
     method public float getResolution();
     method public java.lang.String getStringType();
     method public int getType();
-    method public java.util.UUID getUuid();
     method public java.lang.String getVendor();
     method public int getVersion();
+    method public boolean isAdditionalInfoSupported();
+    method public boolean isDynamicSensor();
     method public boolean isWakeUpSensor();
     field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13644,8 +13648,9 @@
     method public static void getRotationMatrixFromVector(float[], float[]);
     method public java.util.List<android.hardware.Sensor> getSensorList(int);
     method public deprecated int getSensors();
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
-    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback, android.os.Handler);
+    method public boolean isDynamicSensorDiscoverySupported();
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
+    method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int);
     method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
@@ -13654,7 +13659,7 @@
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int, android.os.Handler);
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
-    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorConnectionCallback);
+    method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public deprecated void unregisterListener(android.hardware.SensorListener);
     method public deprecated void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
@@ -13719,8 +13724,8 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorConnectionCallback {
-    ctor public SensorManager.DynamicSensorConnectionCallback();
+  public static abstract class SensorManager.DynamicSensorCallback {
+    ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
   }
@@ -14845,7 +14850,6 @@
 
   public static abstract interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
@@ -14854,7 +14858,6 @@
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
-    field public static final int COUNT = 18; // 0x12
     field public static final int FINAL = 4; // 0x4
     field public static final int FONT = 5; // 0x5
     field public static final int FRACTION = 6; // 0x6
@@ -14874,7 +14877,6 @@
 
   public static abstract interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
-    field public static final int COUNT = 6; // 0x6
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
     field public static final int NARROW = 4; // 0x4
@@ -14884,7 +14886,6 @@
 
   public static abstract interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
-    field public static final int COUNT = 13; // 0xd
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
     field public static final int L = 4; // 0x4
@@ -14900,7 +14901,6 @@
   }
 
   public static abstract interface UCharacter.HangulSyllableType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -14916,7 +14916,6 @@
     field public static final int BEH = 4; // 0x4
     field public static final int BETH = 5; // 0x5
     field public static final int BURUSHASKI_YEH_BARREE = 54; // 0x36
-    field public static final int COUNT = 86; // 0x56
     field public static final int DAL = 6; // 0x6
     field public static final int DALATH_RISH = 7; // 0x7
     field public static final int E = 8; // 0x8
@@ -15001,7 +15000,6 @@
   }
 
   public static abstract interface UCharacter.JoiningType {
-    field public static final int COUNT = 6; // 0x6
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -15024,7 +15022,6 @@
     field public static final int COMPLEX_CONTEXT = 24; // 0x18
     field public static final int CONDITIONAL_JAPANESE_STARTER = 37; // 0x25
     field public static final int CONTINGENT_BREAK = 7; // 0x7
-    field public static final int COUNT = 40; // 0x28
     field public static final int EXCLAMATION = 11; // 0xb
     field public static final int GLUE = 12; // 0xc
     field public static final int H2 = 31; // 0x1f
@@ -15056,7 +15053,6 @@
   }
 
   public static abstract interface UCharacter.NumericType {
-    field public static final int COUNT = 4; // 0x4
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
@@ -15066,7 +15062,6 @@
   public static abstract interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
-    field public static final int COUNT = 15; // 0xf
     field public static final int CR = 11; // 0xb
     field public static final int EXTEND = 12; // 0xc
     field public static final int FORMAT = 3; // 0x3
@@ -15209,7 +15204,6 @@
     field public static final android.icu.lang.UCharacter.UnicodeBlock COPTIC_EPACT_NUMBERS;
     field public static final int COPTIC_EPACT_NUMBERS_ID = 223; // 0xdf
     field public static final int COPTIC_ID = 132; // 0x84
-    field public static final int COUNT = 263; // 0x107
     field public static final android.icu.lang.UCharacter.UnicodeBlock COUNTING_ROD_NUMERALS;
     field public static final int COUNTING_ROD_NUMERALS_ID = 154; // 0x9a
     field public static final android.icu.lang.UCharacter.UnicodeBlock CUNEIFORM;
@@ -15623,7 +15617,6 @@
 
   public static abstract interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
-    field public static final int COUNT = 17; // 0x11
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
     field public static final int EXTEND = 9; // 0x9
@@ -15654,7 +15647,6 @@
   }
 
   public static abstract interface UCharacterEnums.ECharacterCategory {
-    field public static final byte CHAR_CATEGORY_COUNT = 30; // 0x1e
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -15694,7 +15686,6 @@
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
-    field public static final int CHAR_DIRECTION_COUNT = 23; // 0x17
     field public static final int COMMON_NUMBER_SEPARATOR = 6; // 0x6
     field public static final byte DIRECTIONALITY_ARABIC_NUMBER = 5; // 0x5
     field public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 18; // 0x12
@@ -15747,7 +15738,6 @@
     field public static final int BIDI_MIRRORING_GLYPH = 16385; // 0x4001
     field public static final int BIDI_PAIRED_BRACKET = 16397; // 0x400d
     field public static final int BIDI_PAIRED_BRACKET_TYPE = 4117; // 0x1015
-    field public static final int BINARY_LIMIT = 57; // 0x39
     field public static final int BINARY_START = 0; // 0x0
     field public static final int BLOCK = 4097; // 0x1001
     field public static final int CANONICAL_COMBINING_CLASS = 4098; // 0x1002
@@ -15766,7 +15756,6 @@
     field public static final int DEFAULT_IGNORABLE_CODE_POINT = 5; // 0x5
     field public static final int DEPRECATED = 6; // 0x6
     field public static final int DIACRITIC = 7; // 0x7
-    field public static final int DOUBLE_LIMIT = 12289; // 0x3001
     field public static final int DOUBLE_START = 12288; // 0x3000
     field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
     field public static final int EXTENDER = 8; // 0x8
@@ -15785,7 +15774,6 @@
     field public static final int IDS_TRINARY_OPERATOR = 19; // 0x13
     field public static final int ID_CONTINUE = 15; // 0xf
     field public static final int ID_START = 16; // 0x10
-    field public static final int INT_LIMIT = 4118; // 0x1016
     field public static final int INT_START = 4096; // 0x1000
     field public static final int JOINING_GROUP = 4102; // 0x1006
     field public static final int JOINING_TYPE = 4103; // 0x1007
@@ -15795,7 +15783,6 @@
     field public static final int LOGICAL_ORDER_EXCEPTION = 21; // 0x15
     field public static final int LOWERCASE = 22; // 0x16
     field public static final int LOWERCASE_MAPPING = 16388; // 0x4004
-    field public static final int MASK_LIMIT = 8193; // 0x2001
     field public static final int MASK_START = 8192; // 0x2000
     field public static final int MATH = 23; // 0x17
     field public static final int NAME = 16389; // 0x4005
@@ -15810,7 +15797,6 @@
     field public static final int NONCHARACTER_CODE_POINT = 24; // 0x18
     field public static final int NUMERIC_TYPE = 4105; // 0x1009
     field public static final int NUMERIC_VALUE = 12288; // 0x3000
-    field public static final int OTHER_PROPERTY_LIMIT = 28673; // 0x7001
     field public static final int OTHER_PROPERTY_START = 28672; // 0x7000
     field public static final int PATTERN_SYNTAX = 42; // 0x2a
     field public static final int PATTERN_WHITE_SPACE = 43; // 0x2b
@@ -15830,7 +15816,6 @@
     field public static final int SIMPLE_TITLECASE_MAPPING = 16392; // 0x4008
     field public static final int SIMPLE_UPPERCASE_MAPPING = 16393; // 0x4009
     field public static final int SOFT_DOTTED = 27; // 0x1b
-    field public static final int STRING_LIMIT = 16398; // 0x400e
     field public static final int STRING_START = 16384; // 0x4000
     field public static final int S_TERM = 35; // 0x23
     field public static final int TERMINAL_PUNCTUATION = 28; // 0x1c
@@ -15847,7 +15832,6 @@
   }
 
   public static abstract interface UProperty.NameChoice {
-    field public static final int COUNT = 2; // 0x2
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -15892,7 +15876,6 @@
     field public static final int CHAM = 66; // 0x42
     field public static final int CHEROKEE = 6; // 0x6
     field public static final int CIRTH = 67; // 0x43
-    field public static final int CODE_LIMIT = 167; // 0xa7
     field public static final int COMMON = 0; // 0x0
     field public static final int COPTIC = 7; // 0x7
     field public static final int CUNEIFORM = 101; // 0x65
@@ -16287,7 +16270,6 @@
 
   public final class CollationKey implements java.lang.Comparable {
     ctor public CollationKey(java.lang.String, byte[]);
-    ctor public CollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
@@ -16297,7 +16279,6 @@
   }
 
   public static final class CollationKey.BoundMode {
-    field public static final int COUNT = 3; // 0x3
     field public static final int LOWER = 0; // 0x0
     field public static final int UPPER = 1; // 0x1
     field public static final int UPPER_LONG = 2; // 0x2
@@ -16329,7 +16310,6 @@
     method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
     method public static final java.lang.String[] getKeywords();
     method public int getMaxVariable();
-    method public abstract android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public int[] getReorderCodes();
     method public int getStrength();
     method public android.icu.text.UnicodeSet getTailoredSet();
@@ -16369,7 +16349,6 @@
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
     field public static final int FIRST = 4096; // 0x1000
-    field public static final int LIMIT = 4101; // 0x1005
     field public static final int NONE = 103; // 0x67
     field public static final int OTHERS = 103; // 0x67
     field public static final int PUNCTUATION = 4097; // 0x1001
@@ -16482,7 +16461,6 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
-    field public static final int FIELD_COUNT = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16726,7 +16704,6 @@
     field public static final int MONTH = 3; // 0x3
     field public static final int QUARTER = 2; // 0x2
     field public static final int SECOND = 13; // 0xd
-    field public static final int TYPE_LIMIT = 16; // 0x10
     field public static final int WEEKDAY = 6; // 0x6
     field public static final int WEEK_OF_MONTH = 5; // 0x5
     field public static final int WEEK_OF_YEAR = 4; // 0x4
@@ -17357,14 +17334,6 @@
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
-  public final class RawCollationKey extends android.icu.util.ByteArrayWrapper {
-    ctor public RawCollationKey();
-    ctor public RawCollationKey(int);
-    ctor public RawCollationKey(byte[]);
-    ctor public RawCollationKey(byte[], int);
-    method public int compareTo(android.icu.text.RawCollationKey);
-  }
-
   public final class RelativeDateTimeFormatter {
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
@@ -17448,7 +17417,6 @@
     method public android.icu.text.CollationKey getCollationKey(java.lang.String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public android.icu.text.RawCollationKey getRawCollationKey(java.lang.String, android.icu.text.RawCollationKey);
     method public java.lang.String getRules();
     method public java.lang.String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
@@ -17943,19 +17911,6 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public class ByteArrayWrapper implements java.lang.Comparable {
-    ctor public ByteArrayWrapper();
-    ctor public ByteArrayWrapper(byte[], int);
-    ctor public ByteArrayWrapper(java.nio.ByteBuffer);
-    method public final android.icu.util.ByteArrayWrapper append(byte[], int, int);
-    method public int compareTo(android.icu.util.ByteArrayWrapper);
-    method public android.icu.util.ByteArrayWrapper ensureCapacity(int);
-    method public final byte[] releaseBytes();
-    method public final android.icu.util.ByteArrayWrapper set(byte[], int, int);
-    field public byte[] bytes;
-    field public int size;
-  }
-
    abstract class CECalendar extends android.icu.util.Calendar {
     ctor protected CECalendar();
     ctor protected CECalendar(android.icu.util.TimeZone);
@@ -19922,7 +19877,7 @@
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged(android.media.AudioRecordingConfiguration[]);
+    method public void onRecordingConfigChanged(android.media.AudioRecordingConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20199,6 +20154,7 @@
     method public int getAttributeInt(java.lang.String, int);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
+    method public long[] getThumbnailRange();
     method public boolean hasThumbnail();
     method public void saveAttributes() throws java.io.IOException;
     method public void setAttribute(java.lang.String, java.lang.String);
@@ -20211,7 +20167,7 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final java.lang.String TAG_APERTURE = "FNumber";
+    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
     field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
     field public static final java.lang.String TAG_ARTIST = "Artist";
     field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
@@ -20282,7 +20238,7 @@
     field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
     field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
     field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
-    field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
     field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
     field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
     field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
@@ -20690,12 +20646,13 @@
     field public static final int DolbyVisionLevelUhd30 = 64; // 0x40
     field public static final int DolbyVisionLevelUhd48 = 128; // 0x80
     field public static final int DolbyVisionLevelUhd60 = 256; // 0x100
-    field public static final int DolbyVisionProfileDvavDen = 2; // 0x2
-    field public static final int DolbyVisionProfileDvavDer = 1; // 0x1
-    field public static final int DolbyVisionProfileDvheDen = 4; // 0x4
-    field public static final int DolbyVisionProfileDvheDer = 3; // 0x3
-    field public static final int DolbyVisionProfileDvheDtr = 5; // 0x5
-    field public static final int DolbyVisionProfileDvheStn = 6; // 0x6
+    field public static final int DolbyVisionProfileDvavPen = 2; // 0x2
+    field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
+    field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
+    field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+    field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
+    field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
+    field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
     field public static final int H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -28822,6 +28779,7 @@
     field public static final int TEMPERATURE_CURRENT = 0; // 0x0
     field public static final int TEMPERATURE_SHUTDOWN = 2; // 0x2
     field public static final int TEMPERATURE_THROTTLING = 1; // 0x1
+    field public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3; // 0x3
     field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
@@ -29181,6 +29139,7 @@
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
     method public deprecated boolean isScreenOn();
+    method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
@@ -29194,6 +29153,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
@@ -29551,7 +29511,7 @@
     method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
   }
 
-  public class TimerStat implements android.os.Parcelable {
+  public final class TimerStat implements android.os.Parcelable {
     ctor public TimerStat();
     ctor public TimerStat(int, long);
     ctor public TimerStat(android.os.Parcel);
@@ -31998,6 +31958,7 @@
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
     field public static final java.lang.String EXTRA_INFO = "info";
     field public static final java.lang.String EXTRA_LOADING = "loading";
+    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
     field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
     field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
   }
@@ -36842,6 +36803,7 @@
     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 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_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -38030,8 +37992,6 @@
     method public java.lang.String getPackageResourcePath();
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
@@ -44375,6 +44335,7 @@
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityWindowInfo getChild(int);
     method public int getChildCount();
@@ -44382,6 +44343,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
+    method public java.lang.CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -44722,6 +44684,7 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -44889,6 +44852,7 @@
   public abstract interface InputConnection {
     method public abstract boolean beginBatchEdit();
     method public abstract boolean clearMetaKeyStates(int);
+    method public abstract void closeConnection();
     method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
@@ -44921,6 +44885,7 @@
     ctor public InputConnectionWrapper(android.view.inputmethod.InputConnection, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
@@ -49381,9 +49346,7 @@
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
     ctor public FilePermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -50122,6 +50085,7 @@
     method public static int compare(boolean, boolean);
     method public int compareTo(java.lang.Boolean);
     method public static boolean getBoolean(java.lang.String);
+    method public static int hashCode(boolean);
     method public static boolean parseBoolean(java.lang.String);
     method public static java.lang.String toString(boolean);
     method public static java.lang.Boolean valueOf(boolean);
@@ -50139,6 +50103,7 @@
     method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50147,6 +50112,7 @@
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
@@ -50184,6 +50150,7 @@
     method public static int getNumericValue(int);
     method public static int getType(char);
     method public static int getType(int);
+    method public static int hashCode(char);
     method public static char highSurrogate(int);
     method public static boolean isAlphabetic(int);
     method public static boolean isBmpCodePoint(int);
@@ -50244,6 +50211,7 @@
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
     method public static java.lang.Character valueOf(char);
+    field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
     field public static final byte CONTROL = 15; // 0xf
@@ -50870,6 +50838,7 @@
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
     method public float floatValue();
+    method public static int hashCode(float);
     method public static float intBitsToFloat(int);
     method public int intValue();
     method public static boolean isFinite(float);
@@ -50878,11 +50847,15 @@
     method public static boolean isNaN(float);
     method public boolean isNaN();
     method public long longValue();
+    method public static float max(float, float);
+    method public static float min(float, float);
     method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float sum(float, float);
     method public static java.lang.String toHexString(float);
     method public static java.lang.String toString(float);
     method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Float valueOf(float);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
     field public static final int MIN_EXPONENT = -126; // 0xffffff82
@@ -51062,6 +51035,7 @@
     method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Long valueOf(long);
+    field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
@@ -51365,6 +51339,7 @@
     method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
     method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51374,6 +51349,7 @@
     method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Short valueOf(short);
+    field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
@@ -52897,9 +52873,7 @@
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
     ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53981,9 +53955,7 @@
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
     ctor public AllPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -53997,9 +53969,7 @@
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
     ctor public BasicPermission(java.lang.String);
     ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54377,10 +54347,8 @@
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getActions();
     method public final java.lang.String getName();
-    method public abstract int hashCode();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -54638,13 +54606,11 @@
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
     ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
     method public java.lang.String getUnresolvedName();
     method public java.lang.String getUnresolvedType();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
@@ -54702,8 +54668,6 @@
   }
 
   public abstract interface Permission {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String toString();
   }
 
 }
@@ -64012,11 +63976,9 @@
 
   public final class PrivateCredentialPermission extends java.security.Permission {
     ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public boolean equals(java.lang.Object);
     method public java.lang.String getActions();
     method public java.lang.String getCredentialClass();
     method public java.lang.String[][] getPrincipals();
-    method public int hashCode();
     method public boolean implies(java.security.Permission);
   }
 
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 86085c8..3f16bca 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -94,6 +94,10 @@
 
 package android.media.tv {
 
+  public final class TvInputManager {
+    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+  }
+
   public class TvView extends android.view.ViewGroup {
     method public void requestUnblockContent(android.media.tv.TvContentRating);
   }
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 4025553..d44a1df 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -930,7 +930,7 @@
                 // In non-split user mode, userId can only be SYSTEM
                 int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
                 info = mUm.createRestrictedProfile(name, parentUserId);
-                mAm.addSharedAccountsFromParentUser(userId, parentUserId);
+                mAm.addSharedAccountsFromParentUser(parentUserId, userId);
             } else if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index b208e43..0e674c8 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -88,6 +88,8 @@
             runForget();
         } else if ("set-emulate-fbe".equals(op)) {
             runSetEmulateFbe();
+        } else if ("get-fbe-mode".equals(op)) {
+            runGetFbeMode();
         } else {
             throw new IllegalArgumentException();
         }
@@ -145,6 +147,16 @@
                 StorageManager.DEBUG_EMULATE_FBE);
     }
 
+    public void runGetFbeMode() {
+        if (StorageManager.isFileEncryptedNativeOnly()) {
+            System.out.println("native");
+        } else if (StorageManager.isFileEncryptedEmulatedOnly()) {
+            System.out.println("emulated");
+        } else {
+            System.out.println("none");
+        }
+    }
+
     public void runPartition() throws RemoteException {
         final String diskId = nextArg();
         final String type = nextArg();
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4019a56..ee03280 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -36,11 +36,11 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import com.android.internal.R;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -319,6 +319,9 @@
      */
     public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
 
+    /** {@hide} */
+    public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
+
     /**
      * The event types an {@link AccessibilityService} is interested in.
      * <p>
@@ -687,8 +690,9 @@
     }
 
     /** {@hide} */
-    public boolean isEncryptionAware() {
-        return mResolveInfo.serviceInfo.directBootAware;
+    public boolean isDirectBootAware() {
+        return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
+                || mResolveInfo.serviceInfo.directBootAware;
     }
 
     /**
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 7a0c89b..e18a34d 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -36,8 +36,7 @@
  * Accessibility services with the
  * {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
  * gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable; use the {@code create} methods to get common gesture, or a
- * {@code Builder} to create a new one.
+ * Gestures are immutable once built.
  * <p>
  * Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
  */
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index e520b40..7465ed9 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2798,6 +2798,15 @@
         if (account == null) {
             throw new IllegalArgumentException("account is null");
         }
+
+        // Always include the calling package name. This just makes life easier
+        // down stream.
+        final Bundle optionsIn = new Bundle();
+        if (options != null) {
+            optionsIn.putAll(options);
+        }
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
         return new AmsTask(activity, handler, callback) {
             @Override
             public void doWork() throws RemoteException {
@@ -2806,7 +2815,7 @@
                         account,
                         authTokenType,
                         activity != null,
-                        options);
+                        optionsIn);
             }
         }.start();
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0d387e6..0410a6e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -51,12 +51,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
 import android.hardware.input.InputManager;
 import android.media.AudioManager;
 import android.media.session.MediaController;
@@ -121,7 +116,6 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
 import java.io.FileDescriptor;
@@ -1855,15 +1849,15 @@
      * visa-versa.
      * @see android.R.attr#resizeableActivity
      *
-     * @param inMultiWindow True if the activity is in multi-window mode.
+     * @param isInMultiWindowMode True if the activity is in multi-window mode.
      */
     @CallSuper
-    public void onMultiWindowChanged(boolean inMultiWindow) {
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG,
-                "onMultiWindowChanged " + this + ": " + inMultiWindow);
-        mFragments.dispatchMultiWindowChanged(inMultiWindow);
+                "onMultiWindowModeChanged " + this + ": " + isInMultiWindowMode);
+        mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
         if (mWindow != null) {
-            mWindow.onMultiWindowChanged();
+            mWindow.onMultiWindowModeChanged();
         }
     }
 
@@ -1873,9 +1867,9 @@
      *
      * @return True if the activity is in multi-window mode.
      */
-    public boolean inMultiWindow() {
+    public boolean isInMultiWindowMode() {
         try {
-            return ActivityManagerNative.getDefault().inMultiWindow(mToken);
+            return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken);
         } catch (RemoteException e) {
         }
         return false;
@@ -1885,13 +1879,13 @@
      * Called by the system when the activity changes to and from picture-in-picture mode.
      * @see android.R.attr#supportsPictureInPicture
      *
-     * @param inPictureInPicture True if the activity is in picture-in-picture mode.
+     * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
      */
     @CallSuper
-    public void onPictureInPictureChanged(boolean inPictureInPicture) {
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG,
-                "onPictureInPictureChanged " + this + ": " + inPictureInPicture);
-        mFragments.dispatchPictureInPictureChanged(inPictureInPicture);
+                "onPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode);
+        mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
     }
 
     /**
@@ -1900,9 +1894,9 @@
      *
      * @return True if the activity is in picture-in-picture mode.
      */
-    public boolean inPictureInPicture() {
+    public boolean isInPictureInPictureMode() {
         try {
-            return ActivityManagerNative.getDefault().inPictureInPicture(mToken);
+            return ActivityManagerNative.getDefault().isInPictureInPictureMode(mToken);
         } catch (RemoteException e) {
         }
         return false;
@@ -1912,9 +1906,9 @@
      * Puts the activity in picture-in-picture mode.
      * @see android.R.attr#supportsPictureInPicture
      */
-    public void enterPictureInPicture() {
+    public void enterPictureInPictureMode() {
         try {
-            ActivityManagerNative.getDefault().enterPictureInPicture(mToken);
+            ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
         } catch (RemoteException e) {
         }
     }
@@ -6915,14 +6909,25 @@
     }
 
     /**
+     * Check whether the caption on freeform windows is displayed directly on the content.
+     *
+     * @return True if caption is displayed on content, false if it pushes the content down.
+     *
+     * @see {@link #setOverlayWithDecorCaptionEnabled(boolean)}
+     */
+    public boolean isOverlayWithDecorCaptionEnabled() {
+        return mWindow.isOverlayWithDecorCaptionEnabled();
+    }
+
+    /**
      * Set whether the caption should displayed directly on the content rather than push it down.
      *
      * This affects only freeform windows since they display the caption and only the main
      * window of the activity. The caption is used to drag the window around and also shows
      * maximize and close action buttons.
      */
-    public void overlayWithDecorCaption(boolean overlay) {
-        mWindow.setOverlayDecorCaption(overlay);
+    public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
+        mWindow.setOverlayWithDecorCaptionEnabled(enabled);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index baaa55d..d1f5143 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -377,6 +377,12 @@
     /** @hide Process is being cached for later use and is empty. */
     public static final int PROCESS_STATE_CACHED_EMPTY = 16;
 
+    /** @hide The lowest process state number */
+    public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
+
+    /** @hide The highest process state number */
+    public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY;
+
     /** @hide Should this process state be considered a background state? */
     public static final boolean isProcStateBackground(int procState) {
         return procState >= PROCESS_STATE_BACKUP;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4bf48a3..65d48e6 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -95,7 +95,7 @@
         }
         return sSystemReady;
     }
-    static boolean sSystemReady = false;
+    static volatile boolean sSystemReady = false;
 
     static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
         broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
@@ -2890,7 +2890,7 @@
         case IN_MULTI_WINDOW_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
-            final boolean inMultiWindow = inMultiWindow(token);
+            final boolean inMultiWindow = isInMultiWindowMode(token);
             reply.writeNoException();
             reply.writeInt(inMultiWindow ? 1 : 0);
             return true;
@@ -2898,7 +2898,7 @@
         case IN_PICTURE_IN_PICTURE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
-            final boolean inPip = inPictureInPicture(token);
+            final boolean inPip = isInPictureInPictureMode(token);
             reply.writeNoException();
             reply.writeInt(inPip ? 1 : 0);
             return true;
@@ -2906,7 +2906,7 @@
         case ENTER_PICTURE_IN_PICTURE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final IBinder token = data.readStrongBinder();
-            enterPictureInPicture(token);
+            enterPictureInPictureMode(token);
             reply.writeNoException();
             return true;
         }
@@ -6837,7 +6837,7 @@
     }
 
     @Override
-    public boolean inMultiWindow(IBinder token) throws RemoteException {
+    public boolean isInMultiWindowMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6851,7 +6851,7 @@
     }
 
     @Override
-    public boolean inPictureInPicture(IBinder token) throws RemoteException {
+    public boolean isInPictureInPictureMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6865,7 +6865,7 @@
     }
 
     @Override
-    public void enterPictureInPicture(IBinder token) throws RemoteException {
+    public void enterPictureInPictureMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dbc6c84..5b94696 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1284,15 +1284,15 @@
         }
 
         @Override
-        public void scheduleMultiWindowChanged(IBinder token, boolean inMultiWindow)
+        public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode)
                 throws RemoteException {
-            sendMessage(H.MULTI_WINDOW_CHANGED, token, inMultiWindow ? 1 : 0);
+            sendMessage(H.MULTI_WINDOW_MODE_CHANGED, token, isInMultiWindowMode ? 1 : 0);
         }
 
         @Override
-        public void schedulePictureInPictureChanged(IBinder token, boolean inPip)
+        public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
                 throws RemoteException {
-            sendMessage(H.PICTURE_IN_PICTURE_CHANGED, token, inPip ? 1 : 0);
+            sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, token, isInPipMode ? 1 : 0);
         }
 
         @Override
@@ -1364,8 +1364,8 @@
         public static final int ENTER_ANIMATION_COMPLETE = 149;
         public static final int START_BINDER_TRACKING = 150;
         public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
-        public static final int MULTI_WINDOW_CHANGED = 152;
-        public static final int PICTURE_IN_PICTURE_CHANGED = 153;
+        public static final int MULTI_WINDOW_MODE_CHANGED = 152;
+        public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
         public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
 
         String codeToString(int code) {
@@ -1420,8 +1420,8 @@
                     case CANCEL_VISIBLE_BEHIND: return "CANCEL_VISIBLE_BEHIND";
                     case BACKGROUND_VISIBLE_BEHIND_CHANGED: return "BACKGROUND_VISIBLE_BEHIND_CHANGED";
                     case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
-                    case MULTI_WINDOW_CHANGED: return "MULTI_WINDOW_CHANGED";
-                    case PICTURE_IN_PICTURE_CHANGED: return "PICTURE_IN_PICTURE_CHANGED";
+                    case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
+                    case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
                     case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
                 }
             }
@@ -1666,11 +1666,11 @@
                 case STOP_BINDER_TRACKING_AND_DUMP:
                     handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
                     break;
-                case MULTI_WINDOW_CHANGED:
-                    handleMultiWindowChanged((IBinder) msg.obj, msg.arg1 == 1);
+                case MULTI_WINDOW_MODE_CHANGED:
+                    handleMultiWindowModeChanged((IBinder) msg.obj, msg.arg1 == 1);
                     break;
-                case PICTURE_IN_PICTURE_CHANGED:
-                    handlePictureInPictureChanged((IBinder) msg.obj, msg.arg1 == 1);
+                case PICTURE_IN_PICTURE_MODE_CHANGED:
+                    handlePictureInPictureModeChanged((IBinder) msg.obj, msg.arg1 == 1);
                     break;
                 case LOCAL_VOICE_INTERACTION_STARTED:
                     handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
@@ -2924,17 +2924,17 @@
         }
     }
 
-    private void handleMultiWindowChanged(IBinder token, boolean inMultiWindow) {
+    private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
-            r.activity.onMultiWindowChanged(inMultiWindow);
+            r.activity.onMultiWindowModeChanged(isInMultiWindowMode);
         }
     }
 
-    private void handlePictureInPictureChanged(IBinder token, boolean inPip) {
+    private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode) {
         final ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
-            r.activity.onPictureInPictureChanged(inPip);
+            r.activity.onPictureInPictureModeChanged(isInPipMode);
         }
     }
 
@@ -5077,26 +5077,6 @@
          */
         TimeZone.setDefault(null);
 
-        synchronized (mResourcesManager) {
-            /*
-             * Initialize the default locales in this process for the reasons we set the time zone.
-             *
-             * We do this through ResourcesManager, since we need to do locale negotiation.
-             */
-            mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
-
-            /*
-             * Update the system configuration since its preloaded and might not
-             * reflect configuration changes. The configuration object passed
-             * in AppBindData can be safely assumed to be up to date
-             */
-            mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
-            mCurDefaultDisplayDpi = data.config.densityDpi;
-
-            // This calls mResourcesManager so keep it within the synchronized block.
-            applyCompatConfiguration(mCurDefaultDisplayDpi);
-        }
-
         data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
 
         /**
@@ -5221,6 +5201,26 @@
         }
 
         final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
+        synchronized (mResourcesManager) {
+            /*
+             * Initialize the default locales in this process for the reasons we set the time zone.
+             *
+             * We do this through ResourcesManager, since we need to do locale negotiation.
+             */
+            mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
+
+            /*
+             * Update the system configuration since its preloaded and might not
+             * reflect configuration changes. The configuration object passed
+             * in AppBindData can be safely assumed to be up to date
+             */
+            mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
+            mCurDefaultDisplayDpi = data.config.densityDpi;
+
+            // This calls mResourcesManager so keep it within the synchronized block.
+            applyCompatConfiguration(mCurDefaultDisplayDpi);
+        }
+
         if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
             // This cache location probably points at credential-encrypted
             // storage which may not be accessible yet; assign it anyway instead
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index d3ca7ee..4a1aff7 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -239,9 +239,6 @@
     public void onResume(Activity activity, boolean isTopOfTask) {
         // After orientation change, the onResume can come in before the top Activity has
         // left, so if the Activity is not top, wait a second for the top Activity to exit.
-        if (mCalledExitCoordinator == null) {
-            return; // This is the called activity
-        }
         if (isTopOfTask || mEnterTransitionCoordinator == null) {
             restoreExitedViews();
             restoreReenteringViews();
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index cb2130c4..e4fff9d 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -905,10 +905,12 @@
 
         ListenerWrapper wrapper = null;
         synchronized (AlarmManager.class) {
-            final WeakReference<ListenerWrapper> wrapperRef;
-            wrapperRef = sWrappers.get(listener);
-            if (wrapperRef != null) {
-                wrapper = wrapperRef.get();
+            if (sWrappers != null) {
+                final WeakReference<ListenerWrapper> wrapperRef;
+                wrapperRef = sWrappers.get(listener);
+                if (wrapperRef != null) {
+                    wrapper = wrapperRef.get();
+                }
             }
         }
 
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 744ddf7..ea86dd0 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -736,7 +736,7 @@
             data.enforceInterface(IApplicationThread.descriptor);
             final IBinder b = data.readStrongBinder();
             final boolean inMultiWindow = data.readInt() != 0;
-            scheduleMultiWindowChanged(b, inMultiWindow);
+            scheduleMultiWindowModeChanged(b, inMultiWindow);
             return true;
         }
 
@@ -745,7 +745,7 @@
             data.enforceInterface(IApplicationThread.descriptor);
             final IBinder b = data.readStrongBinder();
             final boolean inPip = data.readInt() != 0;
-            schedulePictureInPictureChanged(b, inPip);
+            schedulePictureInPictureModeChanged(b, inPip);
             return true;
         }
 
@@ -1498,24 +1498,24 @@
     }
 
     @Override
-    public final void scheduleMultiWindowChanged(
-            IBinder token, boolean inMultiWindow) throws RemoteException {
+    public final void scheduleMultiWindowModeChanged(
+            IBinder token, boolean isInMultiWindowMode) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
-        data.writeInt(inMultiWindow ? 1 : 0);
+        data.writeInt(isInMultiWindowMode ? 1 : 0);
         mRemote.transact(SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 
     @Override
-    public final void schedulePictureInPictureChanged(IBinder token, boolean inPip)
+    public final void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
-        data.writeInt(inPip ? 1 : 0);
+        data.writeInt(isInPipMode ? 1 : 0);
         mRemote.transact(SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d28f1fb..6bb853a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1993,7 +1993,7 @@
         ContextImpl context = new ContextImpl(null, mainThread,
                 packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
-                context.mResourcesManager.getDisplayMetricsLocked());
+                context.mResourcesManager.getDisplayMetrics());
         return context;
     }
 
@@ -2065,16 +2065,34 @@
                     || overrideConfiguration != null
                     || (compatInfo != null && compatInfo.applicationScale
                             != resources.getCompatibilityInfo().applicationScale)) {
-                resources = mResourcesManager.getResources(
-                        activityToken,
-                        packageInfo.getResDir(),
-                        packageInfo.getSplitResDirs(),
-                        packageInfo.getOverlayDirs(),
-                        packageInfo.getApplicationInfo().sharedLibraryFiles,
-                        displayId,
-                        overrideConfiguration,
-                        compatInfo,
-                        packageInfo.getClassLoader());
+
+                if (container != null) {
+                    // This is a nested Context, so it can't be a base Activity context.
+                    // Just create a regular Resources object associated with the Activity.
+                    resources = mResourcesManager.getResources(
+                            activityToken,
+                            packageInfo.getResDir(),
+                            packageInfo.getSplitResDirs(),
+                            packageInfo.getOverlayDirs(),
+                            packageInfo.getApplicationInfo().sharedLibraryFiles,
+                            displayId,
+                            overrideConfiguration,
+                            compatInfo,
+                            packageInfo.getClassLoader());
+                } else {
+                    // This is not a nested Context, so it must be the root Activity context.
+                    // All other nested Contexts will inherit the configuration set here.
+                    resources = mResourcesManager.createBaseActivityResources(
+                            activityToken,
+                            packageInfo.getResDir(),
+                            packageInfo.getSplitResDirs(),
+                            packageInfo.getOverlayDirs(),
+                            packageInfo.getApplicationInfo().sharedLibraryFiles,
+                            displayId,
+                            overrideConfiguration,
+                            compatInfo,
+                            packageInfo.getClassLoader());
+                }
             }
         }
         mResources = resources;
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 83dc506..bd55a06 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -58,7 +58,7 @@
      * @param context the parent context
      */
     public DatePickerDialog(@NonNull Context context) {
-        this(context, 0);
+        this(context, 0, null, Calendar.getInstance(), -1, -1, -1);
     }
 
     /**
@@ -70,24 +70,7 @@
      *                   {@code context}'s default alert dialog theme
      */
     public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId) {
-        super(context, resolveDialogTheme(context, themeResId));
-
-        final Context themeContext = getContext();
-        final LayoutInflater inflater = LayoutInflater.from(themeContext);
-        final View view = inflater.inflate(R.layout.date_picker_dialog, null);
-        setView(view);
-
-        setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
-        setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
-        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
-
-        final Calendar calendar = Calendar.getInstance();
-        final int year = calendar.get(Calendar.YEAR);
-        final int monthOfYear = calendar.get(Calendar.MONTH);
-        final int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
-        mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
-        mDatePicker.init(year, monthOfYear, dayOfMonth, this);
-        mDatePicker.setValidationCallback(mValidationCallback);
+        this(context, themeResId, null, Calendar.getInstance(), -1, -1, -1);
     }
 
     /**
@@ -104,7 +87,7 @@
      */
     public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener,
             int year, int month, int dayOfMonth) {
-        this(context, 0, listener, year, month, dayOfMonth);
+        this(context, 0, listener, null, year, month, dayOfMonth);
     }
 
     /**
@@ -116,16 +99,40 @@
      *                   {@code context}'s default alert dialog theme
      * @param listener the listener to call when the user sets the date
      * @param year the initially selected year
-     * @param month the initially selected month (0-11 for compatibility with
-     *              {@link Calendar#MONTH})
+     * @param monthOfYear the initially selected month of the year (0-11 for
+     *                    compatibility with {@link Calendar#MONTH})
      * @param dayOfMonth the initially selected day of month (1-31, depending
      *                   on month)
      */
     public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
-            @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
-        this(context, themeResId);
+            @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth) {
+        this(context, themeResId, listener, null, year, monthOfYear, dayOfMonth);
+    }
 
-        mDatePicker.updateDate(year, month, dayOfMonth);
+    private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+            @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year,
+            int monthOfYear, int dayOfMonth) {
+        super(context, resolveDialogTheme(context, themeResId));
+
+        final Context themeContext = getContext();
+        final LayoutInflater inflater = LayoutInflater.from(themeContext);
+        final View view = inflater.inflate(R.layout.date_picker_dialog, null);
+        setView(view);
+
+        setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
+        setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
+        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
+
+        if (calendar != null) {
+            year = calendar.get(Calendar.YEAR);
+            monthOfYear = calendar.get(Calendar.MONTH);
+            dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+        }
+
+        mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
+        mDatePicker.init(year, monthOfYear, dayOfMonth, this);
+        mDatePicker.setValidationCallback(mValidationCallback);
+
         mDateSetListener = listener;
     }
 
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 0bb1097..85a0403 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,10 @@
 
 package android.app;
 
+import com.android.internal.R;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.PhoneWindow;
+
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
@@ -43,7 +47,6 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -57,12 +60,7 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.internal.R;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PhoneWindow;
-
 import java.lang.ref.WeakReference;
-import java.util.List;
 
 /**
  * Base class for Dialogs.
@@ -94,11 +92,14 @@
         KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
     private static final String TAG = "Dialog";
     private Activity mOwnerActivity;
-    
+
+    private final WindowManager mWindowManager;
+
     final Context mContext;
-    final WindowManager mWindowManager;
-    Window mWindow;
+    final Window mWindow;
+
     View mDecor;
+
     private ActionBar mActionBar;
     /**
      * This field should be made private, so it is hidden from the SDK.
@@ -123,7 +124,7 @@
     private static final int CANCEL = 0x44;
     private static final int SHOW = 0x45;
 
-    private Handler mListenersHandler;
+    private final Handler mListenersHandler;
 
     private SearchEvent mSearchEvent;
 
@@ -131,11 +132,7 @@
 
     private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
 
-    private final Runnable mDismissAction = new Runnable() {
-        public void run() {
-            dismissDialog();
-        }
-    };
+    private final Runnable mDismissAction = this::dismissDialog;
 
     /**
      * Creates a dialog window that uses the default dialog theme.
@@ -198,14 +195,15 @@
      * @hide
      */
     @Deprecated
-    protected Dialog(@NonNull Context context, boolean cancelable, Message cancelCallback) {
+    protected Dialog(@NonNull Context context, boolean cancelable,
+            @Nullable Message cancelCallback) {
         this(context);
         mCancelable = cancelable;
         mCancelMessage = cancelCallback;
     }
 
     protected Dialog(@NonNull Context context, boolean cancelable,
-            OnCancelListener cancelListener) {
+            @Nullable OnCancelListener cancelListener) {
         this(context);
         mCancelable = cancelable;
         setOnCancelListener(cancelListener);
@@ -216,8 +214,7 @@
      * 
      * @return Context The Context used by the Dialog.
      */
-    @NonNull
-    public final Context getContext() {
+    public final @NonNull Context getContext() {
         return mContext;
     }
 
@@ -226,7 +223,7 @@
      *
      * @return The ActionBar attached to the dialog or null if no ActionBar is present.
      */
-    public ActionBar getActionBar() {
+    public @Nullable ActionBar getActionBar() {
         return mActionBar;
     }
 
@@ -236,7 +233,7 @@
      * 
      * @param activity The Activity that owns this dialog.
      */
-    public final void setOwnerActivity(Activity activity) {
+    public final void setOwnerActivity(@NonNull Activity activity) {
         mOwnerActivity = activity;
         
         getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
@@ -250,7 +247,7 @@
      * 
      * @return The Activity that owns this Dialog.
      */
-    public final Activity getOwnerActivity() {
+    public final @Nullable Activity getOwnerActivity() {
         return mOwnerActivity;
     }
     
@@ -316,13 +313,10 @@
             l = nl;
         }
 
-        try {
-            mWindowManager.addView(mDecor, l);
-            mShowing = true;
-    
-            sendShowMessage();
-        } finally {
-        }
+        mWindowManager.addView(mDecor, l);
+        mShowing = true;
+
+        sendShowMessage();
     }
     
     /**
@@ -388,7 +382,7 @@
         }
     }
 
-    // internal method to make sure mcreated is set properly without requiring
+    // internal method to make sure mCreated is set properly without requiring
     // users to call through to super in onCreate
     void dispatchOnCreate(Bundle savedInstanceState) {
         if (!mCreated) {
@@ -400,7 +394,7 @@
     /**
      * Similar to {@link Activity#onCreate}, you should initialize your dialog
      * in this method, including calling {@link #setContentView}.
-     * @param savedInstanceState If this dialog is being reinitalized after a
+     * @param savedInstanceState If this dialog is being reinitialized after a
      *     the hosting activity was previously shut down, holds the result from
      *     the most recent call to {@link #onSaveInstanceState}, or null if this
      *     is the first time.
@@ -433,7 +427,7 @@
      * state.
      * @return A bundle with the state of the dialog.
      */
-    public Bundle onSaveInstanceState() {
+    public @NonNull Bundle onSaveInstanceState() {
         Bundle bundle = new Bundle();
         bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
         if (mCreated) {
@@ -452,7 +446,7 @@
      * @param savedInstanceState The state of the dialog previously saved by
      *     {@link #onSaveInstanceState()}.
      */
-    public void onRestoreInstanceState(Bundle savedInstanceState) {
+    public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
         final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
         if (dialogHierarchyState == null) {
             // dialog has never been shown, or onCreated, nothing to restore.
@@ -473,7 +467,7 @@
      * @return Window The current window, or null if the activity is not
      *         visual.
      */
-    public Window getWindow() {
+    public @Nullable Window getWindow() {
         return mWindow;
     }
 
@@ -486,7 +480,7 @@
      * @see #getWindow
      * @see android.view.Window#getCurrentFocus
      */
-    public View getCurrentFocus() {
+    public @Nullable View getCurrentFocus() {
         return mWindow != null ? mWindow.getCurrentFocus() : null;
     }
 
@@ -498,8 +492,7 @@
      * @param id the identifier of the view to find
      * @return The view with the given id or null.
      */
-    @Nullable
-    public View findViewById(@IdRes int id) {
+    public @Nullable View findViewById(@IdRes int id) {
         return mWindow.findViewById(id);
     }
 
@@ -520,19 +513,19 @@
      * 
      * @param view The desired content to display.
      */
-    public void setContentView(View view) {
+    public void setContentView(@NonNull View view) {
         mWindow.setContentView(view);
     }
 
     /**
      * Set the screen content to an explicit view.  This view is placed
      * directly into the screen's view hierarchy.  It can itself be a complex
-     * view hierarhcy.
+     * view hierarchy.
      * 
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      */
-    public void setContentView(View view, ViewGroup.LayoutParams params) {
+    public void setContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
         mWindow.setContentView(view, params);
     }
 
@@ -543,7 +536,7 @@
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      */
-    public void addContentView(View view, ViewGroup.LayoutParams params) {
+    public void addContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
         mWindow.addContentView(view, params);
     }
 
@@ -552,7 +545,7 @@
      * 
      * @param title The new text to display in the title.
      */
-    public void setTitle(CharSequence title) {
+    public void setTitle(@Nullable CharSequence title) {
         mWindow.setTitle(title);
         mWindow.getAttributes().setTitle(title);
     }
@@ -578,7 +571,8 @@
      * @see #onKeyUp
      * @see android.view.KeyEvent
      */
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
+    @Override
+    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
             event.startTracking();
             return true;
@@ -592,7 +586,8 @@
      * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
      * the event).
      */
-    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+    @Override
+    public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
         return false;
     }
 
@@ -605,7 +600,8 @@
      * @see #onKeyDown
      * @see KeyEvent
      */
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
+    @Override
+    public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
                 && !event.isCanceled()) {
             onBackPressed();
@@ -619,7 +615,8 @@
      * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
      * the event).
      */
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+    @Override
+    public boolean onKeyMultiple(int keyCode, int repeatCount, @NonNull KeyEvent event) {
         return false;
     }
     
@@ -644,7 +641,7 @@
      * @param event Description of the key event.
      * @return True if the key shortcut was handled.
      */
-    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+    public boolean onKeyShortcut(int keyCode, @NonNull KeyEvent event) {
         return false;
     }
 
@@ -658,7 +655,7 @@
      *         The default implementation will cancel the dialog when a touch
      *         happens outside of the window bounds.
      */
-    public boolean onTouchEvent(MotionEvent event) {
+    public boolean onTouchEvent(@NonNull MotionEvent event) {
         if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {
             cancel();
             return true;
@@ -681,7 +678,7 @@
      * @return Return true if you have consumed the event, false if you haven't.
      * The default implementation always returns false.
      */
-    public boolean onTrackballEvent(MotionEvent event) {
+    public boolean onTrackballEvent(@NonNull MotionEvent event) {
         return false;
     }
 
@@ -710,25 +707,30 @@
      * @return Return true if you have consumed the event, false if you haven't.
      * The default implementation always returns false.
      */
-    public boolean onGenericMotionEvent(MotionEvent event) {
+    public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
         return false;
     }
 
+    @Override
     public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
         if (mDecor != null) {
             mWindowManager.updateViewLayout(mDecor, params);
         }
     }
 
+    @Override
     public void onContentChanged() {
     }
 
+    @Override
     public void onWindowFocusChanged(boolean hasFocus) {
     }
 
+    @Override
     public void onAttachedToWindow() {
     }
 
+    @Override
     public void onDetachedFromWindow() {
     }
 
@@ -747,7 +749,8 @@
      *
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchKeyEvent(KeyEvent event) {
+    @Override
+    public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
         if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {
             return true;
         }
@@ -767,7 +770,8 @@
      * @param event The key shortcut event.
      * @return True if this event was consumed.
      */
-    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+    @Override
+    public boolean dispatchKeyShortcutEvent(@NonNull KeyEvent event) {
         if (mWindow.superDispatchKeyShortcutEvent(event)) {
             return true;
         }
@@ -784,7 +788,8 @@
      * 
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchTouchEvent(MotionEvent ev) {
+    @Override
+    public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
         if (mWindow.superDispatchTouchEvent(ev)) {
             return true;
         }
@@ -801,7 +806,8 @@
      * 
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchTrackballEvent(MotionEvent ev) {
+    @Override
+    public boolean dispatchTrackballEvent(@NonNull MotionEvent ev) {
         if (mWindow.superDispatchTrackballEvent(ev)) {
             return true;
         }
@@ -818,14 +824,16 @@
      *
      * @return boolean Return true if this event was consumed.
      */
-    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+    @Override
+    public boolean dispatchGenericMotionEvent(@NonNull MotionEvent ev) {
         if (mWindow.superDispatchGenericMotionEvent(ev)) {
             return true;
         }
         return onGenericMotionEvent(ev);
     }
 
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
         event.setClassName(getClass().getName());
         event.setPackageName(mContext.getPackageName());
 
@@ -840,6 +848,7 @@
     /**
      * @see Activity#onCreatePanelView(int)
      */
+    @Override
     public View onCreatePanelView(int featureId) {
         return null;
     }
@@ -847,7 +856,8 @@
     /**
      * @see Activity#onCreatePanelMenu(int, Menu)
      */
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+    @Override
+    public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             return onCreateOptionsMenu(menu);
         }
@@ -858,10 +868,10 @@
     /**
      * @see Activity#onPreparePanel(int, View, Menu)
      */
+    @Override
     public boolean onPreparePanel(int featureId, View view, Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
-            boolean goforit = onPrepareOptionsMenu(menu);
-            return goforit && menu.hasVisibleItems();
+            return onPrepareOptionsMenu(menu) && menu.hasVisibleItems();
         }
         return true;
     }
@@ -869,6 +879,7 @@
     /**
      * @see Activity#onMenuOpened(int, Menu)
      */
+    @Override
     public boolean onMenuOpened(int featureId, Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(true);
@@ -879,6 +890,7 @@
     /**
      * @see Activity#onMenuItemSelected(int, MenuItem)
      */
+    @Override
     public boolean onMenuItemSelected(int featureId, MenuItem item) {
         return false;
     }
@@ -886,6 +898,7 @@
     /**
      * @see Activity#onPanelClosed(int, Menu)
      */
+    @Override
     public void onPanelClosed(int featureId, Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(false);
@@ -900,7 +913,7 @@
      * @see Activity#onCreateOptionsMenu(Menu)
      * @see #getOwnerActivity()
      */
-    public boolean onCreateOptionsMenu(Menu menu) {
+    public boolean onCreateOptionsMenu(@NonNull Menu menu) {
         return true;
     }
 
@@ -912,21 +925,21 @@
      * @see Activity#onPrepareOptionsMenu(Menu)
      * @see #getOwnerActivity()
      */
-    public boolean onPrepareOptionsMenu(Menu menu) {
+    public boolean onPrepareOptionsMenu(@NonNull Menu menu) {
         return true;
     }
 
     /**
      * @see Activity#onOptionsItemSelected(MenuItem)
      */
-    public boolean onOptionsItemSelected(MenuItem item) {
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         return false;
     }
 
     /**
      * @see Activity#onOptionsMenuClosed(Menu)
      */
-    public void onOptionsMenuClosed(Menu menu) {
+    public void onOptionsMenuClosed(@NonNull Menu menu) {
     }
 
     /**
@@ -959,47 +972,49 @@
     /**
      * @see Activity#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)
      */
+    @Override
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
     }
 
     /**
      * @see Activity#registerForContextMenu(View)
      */
-    public void registerForContextMenu(View view) {
+    public void registerForContextMenu(@NonNull View view) {
         view.setOnCreateContextMenuListener(this);
     }
     
     /**
      * @see Activity#unregisterForContextMenu(View)
      */
-    public void unregisterForContextMenu(View view) {
+    public void unregisterForContextMenu(@NonNull View view) {
         view.setOnCreateContextMenuListener(null);
     }
     
     /**
      * @see Activity#openContextMenu(View)
      */
-    public void openContextMenu(View view) {
+    public void openContextMenu(@NonNull View view) {
         view.showContextMenu();
     }
 
     /**
      * @see Activity#onContextItemSelected(MenuItem)
      */
-    public boolean onContextItemSelected(MenuItem item) {
+    public boolean onContextItemSelected(@NonNull MenuItem item) {
         return false;
     }
 
     /**
      * @see Activity#onContextMenuClosed(Menu)
      */
-    public void onContextMenuClosed(Menu menu) {
+    public void onContextMenuClosed(@NonNull Menu menu) {
     }
 
     /**
      * This hook is called when the user signals the desire to start a search.
      */
-    public boolean onSearchRequested(SearchEvent searchEvent) {
+    @Override
+    public boolean onSearchRequested(@NonNull SearchEvent searchEvent) {
         mSearchEvent = searchEvent;
         return onSearchRequested();
     }
@@ -1007,6 +1022,7 @@
     /**
      * This hook is called when the user signals the desire to start a search.
      */
+    @Override
     public boolean onSearchRequested() {
         final SearchManager searchManager = (SearchManager) mContext
                 .getSystemService(Context.SEARCH_SERVICE);
@@ -1029,13 +1045,10 @@
      * @return SearchEvent The SearchEvent that triggered the {@link
      *                    #onSearchRequested} callback.
      */
-    public final SearchEvent getSearchEvent() {
+    public final @Nullable SearchEvent getSearchEvent() {
         return mSearchEvent;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         if (mActionBar != null && mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) {
@@ -1044,9 +1057,6 @@
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
         try {
@@ -1063,6 +1073,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeStarted(mode).
      */
+    @Override
     @CallSuper
     public void onActionModeStarted(ActionMode mode) {
         mActionMode = mode;
@@ -1074,6 +1085,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeFinished(mode).
      */
+    @Override
     @CallSuper
     public void onActionModeFinished(ActionMode mode) {
         if (mode == mActionMode) {
@@ -1139,7 +1151,7 @@
      * Convenience for calling
      * {@link android.view.Window#setFeatureDrawableUri}.
      */
-    public final void setFeatureDrawableUri(int featureId, Uri uri) {
+    public final void setFeatureDrawableUri(int featureId, @Nullable Uri uri) {
         getWindow().setFeatureDrawableUri(featureId, uri);
     }
 
@@ -1147,7 +1159,7 @@
      * Convenience for calling
      * {@link android.view.Window#setFeatureDrawable(int, Drawable)}.
      */
-    public final void setFeatureDrawable(int featureId, Drawable drawable) {
+    public final void setFeatureDrawable(int featureId, @Nullable Drawable drawable) {
         getWindow().setFeatureDrawable(featureId, drawable);
     }
 
@@ -1159,7 +1171,7 @@
         getWindow().setFeatureDrawableAlpha(featureId, alpha);
     }
 
-    public LayoutInflater getLayoutInflater() {
+    public @NonNull LayoutInflater getLayoutInflater() {
         return getWindow().getLayoutInflater();
     }
 
@@ -1191,6 +1203,7 @@
      * Cancel the dialog.  This is essentially the same as calling {@link #dismiss()}, but it will
      * also call your {@link DialogInterface.OnCancelListener} (if registered).
      */
+    @Override
     public void cancel() {
         if (!mCanceled && mCancelMessage != null) {
             mCanceled = true;
@@ -1211,7 +1224,7 @@
      * 
      * @param listener The {@link DialogInterface.OnCancelListener} to use.
      */
-    public void setOnCancelListener(final OnCancelListener listener) {
+    public void setOnCancelListener(@Nullable OnCancelListener listener) {
         if (mCancelAndDismissTaken != null) {
             throw new IllegalStateException(
                     "OnCancelListener is already taken by "
@@ -1229,7 +1242,7 @@
      * @param msg The msg to send when the dialog is canceled.
      * @see #setOnCancelListener(android.content.DialogInterface.OnCancelListener)
      */
-    public void setCancelMessage(final Message msg) {
+    public void setCancelMessage(@Nullable Message msg) {
         mCancelMessage = msg;
     }
 
@@ -1237,7 +1250,7 @@
      * Set a listener to be invoked when the dialog is dismissed.
      * @param listener The {@link DialogInterface.OnDismissListener} to use.
      */
-    public void setOnDismissListener(final OnDismissListener listener) {
+    public void setOnDismissListener(@Nullable OnDismissListener listener) {
         if (mCancelAndDismissTaken != null) {
             throw new IllegalStateException(
                     "OnDismissListener is already taken by "
@@ -1254,7 +1267,7 @@
      * Sets a listener to be invoked when the dialog is shown.
      * @param listener The {@link DialogInterface.OnShowListener} to use.
      */
-    public void setOnShowListener(OnShowListener listener) {
+    public void setOnShowListener(@Nullable OnShowListener listener) {
         if (listener != null) {
             mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
         } else {
@@ -1266,13 +1279,13 @@
      * Set a message to be sent when the dialog is dismissed.
      * @param msg The msg to send when the dialog is dismissed.
      */
-    public void setDismissMessage(final Message msg) {
+    public void setDismissMessage(@Nullable Message msg) {
         mDismissMessage = msg;
     }
 
     /** @hide */
-    public boolean takeCancelAndDismissListeners(String msg, final OnCancelListener cancel,
-            final OnDismissListener dismiss) {
+    public boolean takeCancelAndDismissListeners(@Nullable String msg,
+            @Nullable OnCancelListener cancel, @Nullable OnDismissListener dismiss) {
         if (mCancelAndDismissTaken != null) {
             mCancelAndDismissTaken = null;
         } else if (mCancelMessage != null || mDismissMessage != null) {
@@ -1306,15 +1319,15 @@
     /**
      * Sets the callback that will be called if a key is dispatched to the dialog.
      */
-    public void setOnKeyListener(final OnKeyListener onKeyListener) {
+    public void setOnKeyListener(@Nullable OnKeyListener onKeyListener) {
         mOnKeyListener = onKeyListener;
     }
 
     private static final class ListenersHandler extends Handler {
-        private WeakReference<DialogInterface> mDialog;
+        private final WeakReference<DialogInterface> mDialog;
 
         public ListenersHandler(Dialog dialog) {
-            mDialog = new WeakReference<DialogInterface>(dialog);
+            mDialog = new WeakReference<>(dialog);
         }
 
         @Override
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 8bc1aa3..e681d47 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1380,7 +1380,7 @@
             if (destinationType == Downloads.Impl.DESTINATION_FILE_URI ||
                     destinationType == Downloads.Impl.DESTINATION_EXTERNAL ||
                     destinationType == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) {
-                String localPath = getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
+                String localPath = super.getString(getColumnIndex(COLUMN_LOCAL_FILENAME));
                 if (localPath == null) {
                     return null;
                 }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f7a4557..c745644 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1033,11 +1033,11 @@
      *                        false if it is not.
      */
     public void setUserVisibleHint(boolean isVisibleToUser) {
-        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null) {
+        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && isAdded()) {
             mFragmentManager.performPendingDeferredStart(this);
         }
         mUserVisibleHint = isVisibleToUser;
-        mDeferStart = !isVisibleToUser;
+        mDeferStart = mState < STARTED && !isVisibleToUser;
     }
 
     /**
@@ -1582,21 +1582,21 @@
 
     /**
      * Called when the Fragment's activity changes from fullscreen mode to multi-window mode and
-     * visa-versa. This is generally tied to {@link Activity#onMultiWindowChanged} of the containing
-     * Activity.
+     * visa-versa. This is generally tied to {@link Activity#onMultiWindowModeChanged} of the
+     * containing Activity.
      *
-     * @param inMultiWindow True if the activity is in multi-window mode.
+     * @param isInMultiWindowMode True if the activity is in multi-window mode.
      */
-    public void onMultiWindowChanged(boolean inMultiWindow) {
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
     }
 
     /**
      * Called by the system when the activity changes to and from picture-in-picture mode. This is
-     * generally tied to {@link Activity#onPictureInPictureChanged} of the containing Activity.
+     * generally tied to {@link Activity#onPictureInPictureModeChanged} of the containing Activity.
      *
-     * @param inPictureInPicture True if the activity is in picture-in-picture mode.
+     * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
      */
-    public void onPictureInPictureChanged(boolean inPictureInPicture) {
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
     }
 
     public void onConfigurationChanged(Configuration newConfig) {
@@ -2334,17 +2334,17 @@
         }
     }
 
-    void performMultiWindowChanged(boolean inMultiWindow) {
-        onMultiWindowChanged(inMultiWindow);
+    void performMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        onMultiWindowModeChanged(isInMultiWindowMode);
         if (mChildFragmentManager != null) {
-            mChildFragmentManager.dispatchMultiWindowChanged(inMultiWindow);
+            mChildFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode);
         }
     }
 
-    void performPictureInPictureChanged(boolean inPictureInPicture) {
-        onPictureInPictureChanged(inPictureInPicture);
+    void performPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        onPictureInPictureModeChanged(isInPictureInPictureMode);
         if (mChildFragmentManager != null) {
-            mChildFragmentManager.dispatchPictureInPictureChanged(inPictureInPicture);
+            mChildFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
         }
     }
 
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 57b0ff1..b3d2df5 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -247,10 +247,10 @@
      * the activity changed.
      * <p>Call when the multi-window mode of the activity changed.
      *
-     * @see Fragment#onMultiWindowChanged
+     * @see Fragment#onMultiWindowModeChanged
      */
-    public void dispatchMultiWindowChanged(boolean inMultiWindow) {
-        mHost.mFragmentManager.dispatchMultiWindowChanged(inMultiWindow);
+    public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        mHost.mFragmentManager.dispatchMultiWindowModeChanged(isInMultiWindowMode);
     }
 
     /**
@@ -258,10 +258,10 @@
      * mode of the activity changed.
      * <p>Call when the picture-in-picture mode of the activity changed.
      *
-     * @see Fragment#onPictureInPictureChanged
+     * @see Fragment#onPictureInPictureModeChanged
      */
-    public void dispatchPictureInPictureChanged(boolean inPictureInPicture) {
-        mHost.mFragmentManager.dispatchPictureInPictureChanged(inPictureInPicture);
+    public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        mHost.mFragmentManager.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
     }
 
     /**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 2852baf..8369f17 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2069,26 +2069,26 @@
         mParent = null;
     }
 
-    public void dispatchMultiWindowChanged(boolean inMultiWindow) {
+    public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
         if (mAdded == null) {
             return;
         }
         for (int i = mAdded.size() - 1; i >= 0; --i) {
             final Fragment f = mAdded.get(i);
             if (f != null) {
-                f.performMultiWindowChanged(inMultiWindow);
+                f.performMultiWindowModeChanged(isInMultiWindowMode);
             }
         }
     }
 
-    public void dispatchPictureInPictureChanged(boolean inPictureInPicture) {
+    public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         if (mAdded == null) {
             return;
         }
         for (int i = mAdded.size() - 1; i >= 0; --i) {
             final Fragment f = mAdded.get(i);
             if (f != null) {
-                f.performPictureInPictureChanged(inPictureInPicture);
+                f.performPictureInPictureModeChanged(isInPictureInPictureMode);
             }
         }
     }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 417c0679..8ee6fd0 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -623,11 +623,11 @@
 
     public int getAppStartMode(int uid, String packageName) throws RemoteException;
 
-    public boolean inMultiWindow(IBinder token) throws RemoteException;
+    public boolean isInMultiWindowMode(IBinder token) throws RemoteException;
 
-    public boolean inPictureInPicture(IBinder token) throws RemoteException;
+    public boolean isInPictureInPictureMode(IBinder token) throws RemoteException;
 
-    public void enterPictureInPicture(IBinder token) throws RemoteException;
+    public void enterPictureInPictureMode(IBinder token) throws RemoteException;
 
     public int setVrMode(IBinder token, boolean enabled, ComponentName packageName)
             throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 628bde0..a3b2638 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -158,8 +158,8 @@
     void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException;
     void startBinderTracking() throws RemoteException;
     void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException;
-    void scheduleMultiWindowChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
-    void schedulePictureInPictureChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
+    void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) throws RemoteException;
+    void schedulePictureInPictureModeChanged(IBinder token, boolean isInPictureInPictureMode) throws RemoteException;
     void scheduleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor voiceInteractor) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 54d813d..4c4f128 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -66,7 +66,7 @@
                 }
             };
 
-    private String[] mSystemLocales = {};
+    private String[] mSystemLocales = null;
     private final HashSet<String> mNonSystemLocales = new HashSet<>();
     private boolean mHasNonSystemLocales = false;
 
@@ -94,9 +94,18 @@
     private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
 
     /**
-     * Each Activity may have only one Resources object.
+     * Resources and base configuration override associated with an Activity.
      */
-    private final WeakHashMap<IBinder, WeakReference<Resources>> mActivityResourceReferences =
+    private static class ActivityResources {
+        public final Configuration overrideConfig = new Configuration();
+        public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
+    }
+
+    /**
+     * Each Activity may has a base override configuration that is applied to each Resources object,
+     * which in turn may have their own override configuration specified.
+     */
+    private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences =
             new WeakHashMap<>();
 
     /**
@@ -115,18 +124,20 @@
     }
 
     public Configuration getConfiguration() {
-        return mResConfiguration;
+        synchronized (this) {
+            return mResConfiguration;
+        }
     }
 
-    DisplayMetrics getDisplayMetricsLocked() {
-        return getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+    DisplayMetrics getDisplayMetrics() {
+        return getDisplayMetrics(Display.DEFAULT_DISPLAY);
     }
 
     /**
      * Protected so that tests can override and returns something a fixed value.
      */
     @VisibleForTesting
-    protected DisplayMetrics getDisplayMetricsLocked(int displayId) {
+    protected DisplayMetrics getDisplayMetrics(int displayId) {
         DisplayMetrics dm = new DisplayMetrics();
         final Display display =
                 getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
@@ -272,10 +283,9 @@
         return config;
     }
 
-
     private ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
         AssetManager assets = createAssetManager(key);
-        DisplayMetrics dm = getDisplayMetricsLocked(key.mDisplayId);
+        DisplayMetrics dm = getDisplayMetrics(key.mDisplayId);
         Configuration config = generateConfig(key, dm);
         ResourcesImpl impl = new ResourcesImpl(assets, dm, config, key.mCompatInfo);
         if (DEBUG) {
@@ -290,7 +300,7 @@
      * @param key The key to match.
      * @return a ResourcesImpl if the key matches a cache entry, null otherwise.
      */
-    private ResourcesImpl findResourcesImplForKey(@NonNull ResourcesKey key) {
+    private ResourcesImpl findResourcesImplForKeyLocked(@NonNull ResourcesKey key) {
         WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.get(key);
         ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
         if (impl != null && impl.getAssets().isUpToDate()) {
@@ -303,7 +313,7 @@
      * Find the ResourcesKey that this ResourcesImpl object is associated with.
      * @return the ResourcesKey or null if none was found.
      */
-    private ResourcesKey findKeyForResourceImpl(@NonNull ResourcesImpl resourceImpl) {
+    private ResourcesKey findKeyForResourceImplLocked(@NonNull ResourcesImpl resourceImpl) {
         final int refCount = mResourceImpls.size();
         for (int i = 0; i < refCount; i++) {
             WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
@@ -315,36 +325,46 @@
         return null;
     }
 
+    private ActivityResources getOrCreateActivityResourcesStructLocked(
+            @NonNull IBinder activityToken) {
+        ActivityResources activityResources = mActivityResourceReferences.get(activityToken);
+        if (activityResources == null) {
+            activityResources = new ActivityResources();
+            mActivityResourceReferences.put(activityToken, activityResources);
+        }
+        return activityResources;
+    }
+
     /**
      * Gets an existing Resources object tied to this Activity, or creates one if it doesn't exist
      * or the class loader is different.
      */
     private Resources getOrCreateResourcesForActivityLocked(@NonNull IBinder activityToken,
             @NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl) {
-        // This is a request tied to an Activity, meaning we will need to update all
-        // Activity related Resources to match this configuration.
-        WeakReference<Resources> weakResourceRef = mActivityResourceReferences.get(activityToken);
-        Resources resources = weakResourceRef != null ? weakResourceRef.get() : null;
-        if (resources == null || !Objects.equals(resources.getClassLoader(), classLoader)) {
-            resources = new Resources(classLoader);
-            mActivityResourceReferences.put(activityToken, new WeakReference<>(resources));
-            if (DEBUG) {
-                Slog.d(TAG, "- creating new ref=" + resources);
-            }
-        } else {
-            if (DEBUG) {
-                Slog.d(TAG, "- using existing ref=" + resources);
+        final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                activityToken);
+
+        final int refCount = activityResources.activityResources.size();
+        for (int i = 0; i < refCount; i++) {
+            WeakReference<Resources> weakResourceRef = activityResources.activityResources.get(i);
+            Resources resources = weakResourceRef.get();
+
+            if (resources != null
+                    && Objects.equals(resources.getClassLoader(), classLoader)
+                    && resources.getImpl() == impl) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- using existing ref=" + resources);
+                }
+                return resources;
             }
         }
 
-        if (resources.getImpl() != impl) {
-            if (DEBUG) {
-                Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
-            }
-
-            // Setting an impl is expensive because we update all ThemeImpl references.
-            // too.
-            resources.setImpl(impl);
+        Resources resources = new Resources(classLoader);
+        resources.setImpl(impl);
+        activityResources.activityResources.add(new WeakReference<>(resources));
+        if (DEBUG) {
+            Slog.d(TAG, "- creating new ref=" + resources);
+            Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
         }
         return resources;
     }
@@ -359,7 +379,7 @@
         final int refCount = mResourceReferences.size();
         for (int i = 0; i < refCount; i++) {
             WeakReference<Resources> weakResourceRef = mResourceReferences.get(i);
-            Resources resources = weakResourceRef != null ? weakResourceRef.get() : null;
+            Resources resources = weakResourceRef.get();
             if (resources != null &&
                     Objects.equals(resources.getClassLoader(), classLoader) &&
                     resources.getImpl() == impl) {
@@ -382,6 +402,182 @@
     }
 
     /**
+     * Creates base resources for an Activity. Calls to
+     * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
+     * CompatibilityInfo, ClassLoader)} with the same activityToken will have their override
+     * configurations merged with the one specified here.
+     *
+     * @param activityToken Represents an Activity.
+     * @param resDir The base resource path. Can be null (only framework resources will be loaded).
+     * @param splitResDirs An array of split resource paths. Can be null.
+     * @param overlayDirs An array of overlay paths. Can be null.
+     * @param libDirs An array of resource library paths. Can be null.
+     * @param displayId The ID of the display for which to create the resources.
+     * @param overrideConfig The configuration to apply on top of the base configuration. Can be
+     *                       null. This provides the base override for this Activity.
+     * @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
+     *                   {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
+     * @param classLoader The class loader to use when inflating Resources. If null, the
+     *                    {@link ClassLoader#getSystemClassLoader()} is used.
+     * @return a Resources object from which to access resources.
+     */
+    public Resources createBaseActivityResources(@NonNull IBinder activityToken,
+            @Nullable String resDir,
+            @Nullable String[] splitResDirs,
+            @Nullable String[] overlayDirs,
+            @Nullable String[] libDirs,
+            int displayId,
+            @Nullable Configuration overrideConfig,
+            @NonNull CompatibilityInfo compatInfo,
+            @Nullable ClassLoader classLoader) {
+        final ResourcesKey key = new ResourcesKey(
+                resDir,
+                splitResDirs,
+                overlayDirs,
+                libDirs,
+                displayId,
+                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                compatInfo);
+        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+
+        if (DEBUG) {
+            Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+                    + " with key=" + key);
+        }
+
+        synchronized (this) {
+            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                    activityToken);
+
+            if (overrideConfig != null) {
+                activityResources.overrideConfig.setTo(overrideConfig);
+            } else {
+                activityResources.overrideConfig.setToDefaults();
+            }
+        }
+
+        // Update any existing Activity Resources references.
+        updateResourcesForActivity(activityToken, overrideConfig);
+
+        // Now request an actual Resources object.
+        return getOrCreateResources(activityToken, key, classLoader);
+    }
+
+    /**
+     * Gets an existing Resources object set with a ResourcesImpl object matching the given key,
+     * or creates one if it doesn't exist.
+     *
+     * @param activityToken The Activity this Resources object should be associated with.
+     * @param key The key describing the parameters of the ResourcesImpl object.
+     * @param classLoader The classloader to use for the Resources object.
+     *                    If null, {@link ClassLoader#getSystemClassLoader()} is used.
+     * @return A Resources object that gets updated when
+     *         {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
+     *         is called.
+     */
+    private Resources getOrCreateResources(@Nullable IBinder activityToken,
+            @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
+        final boolean findSystemLocales;
+        final boolean hasNonSystemLocales;
+        synchronized (this) {
+            findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0);
+            hasNonSystemLocales = mHasNonSystemLocales;
+
+            if (DEBUG) {
+                Throwable here = new Throwable();
+                here.fillInStackTrace();
+                Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
+            }
+
+            if (activityToken != null) {
+                final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                        activityToken);
+
+                // Clean up any dead references so they don't pile up.
+                ArrayUtils.unstableRemoveIf(activityResources.activityResources,
+                        sEmptyReferencePredicate);
+
+                // Rebase the key's override config on top of the Activity's base override.
+                if (key.hasOverrideConfiguration()
+                        && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
+                    final Configuration temp = new Configuration(activityResources.overrideConfig);
+                    temp.updateFrom(key.mOverrideConfiguration);
+                    key.mOverrideConfiguration.setTo(temp);
+                }
+
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
+                if (resourcesImpl != null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "- using existing impl=" + resourcesImpl);
+                    }
+                    return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
+                            resourcesImpl);
+                }
+
+                // We will create the ResourcesImpl object outside of holding this lock.
+
+            } else {
+                // Clean up any dead references so they don't pile up.
+                ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
+
+                // Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
+                if (resourcesImpl != null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "- using existing impl=" + resourcesImpl);
+                    }
+                    return getOrCreateResourcesLocked(classLoader, resourcesImpl);
+                }
+
+                // We will create the ResourcesImpl object outside of holding this lock.
+            }
+        }
+
+        // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+        ResourcesImpl resourcesImpl = createResourcesImpl(key);
+
+        final String[] systemLocales = findSystemLocales
+                ? AssetManager.getSystem().getLocales() : null;
+        final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
+        // Avoid checking for non-pseudo-locales if we already know there were some from a previous
+        // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
+        // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
+        // able to affect mHasNonSystemLocales.
+        final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
+                LocaleList.isPseudoLocalesOnly(nonSystemLocales);
+
+        synchronized (this) {
+            if (mSystemLocales == null || mSystemLocales.length == 0) {
+                mSystemLocales = systemLocales;
+            }
+            mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
+            mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
+
+            ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
+            if (existingResourcesImpl != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
+                            + " new impl=" + resourcesImpl);
+                }
+                resourcesImpl.getAssets().close();
+                resourcesImpl = existingResourcesImpl;
+            } else {
+                // Add this ResourcesImpl to the cache.
+                mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
+            }
+
+            final Resources resources;
+            if (activityToken != null) {
+                resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
+                        resourcesImpl);
+            } else {
+                resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
+            }
+            return resources;
+        }
+    }
+
+    /**
      * Gets or creates a new Resources object associated with the IBinder token. References returned
      * by this method live as long as the Activity, meaning they can be cached and used by the
      * Activity even after a configuration change. If any other parameter is changed
@@ -425,92 +621,8 @@
                 displayId,
                 overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
                 compatInfo);
-
         classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
-
-        final boolean findSystemLocales;
-        final boolean hasNonSystemLocales;
-        synchronized (this) {
-            findSystemLocales = (mSystemLocales.length == 0);
-            hasNonSystemLocales = mHasNonSystemLocales;
-
-            if (DEBUG) {
-                Throwable here = new Throwable();
-                here.fillInStackTrace();
-                Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
-            }
-
-            if (activityToken != null) {
-                ResourcesImpl resourcesImpl = findResourcesImplForKey(key);
-                if (resourcesImpl != null) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "- using existing impl=" + resourcesImpl);
-                    }
-                    return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
-                            resourcesImpl);
-                }
-
-                // We will create the ResourcesImpl object outside of holding this lock.
-
-            } else {
-                // Clean up any dead references so they don't pile up.
-                ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
-
-                // Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
-                ResourcesImpl resourcesImpl = findResourcesImplForKey(key);
-                if (resourcesImpl != null) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "- using existing impl=" + resourcesImpl);
-                    }
-                    return getOrCreateResourcesLocked(classLoader, resourcesImpl);
-                }
-
-                // We will create the ResourcesImpl object outside of holding this lock.
-            }
-        }
-
-        // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
-        ResourcesImpl resourcesImpl = createResourcesImpl(key);
-
-        final String[] systemLocales = findSystemLocales
-                ? AssetManager.getSystem().getLocales() : null;
-        final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
-        // Avoid checking for non-pseudo-locales if we already know there were some from a previous
-        // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
-        // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
-        // able to affect mHasNonSystemLocales.
-        final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
-                LocaleList.isPseudoLocalesOnly(nonSystemLocales);
-
-        synchronized (this) {
-            if (mSystemLocales.length == 0) {
-                mSystemLocales = systemLocales;
-            }
-            mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
-            mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
-
-            ResourcesImpl existingResourcesImpl = findResourcesImplForKey(key);
-            if (existingResourcesImpl != null) {
-                if (DEBUG) {
-                    Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
-                            + " new impl=" + resourcesImpl);
-                }
-                resourcesImpl.getAssets().close();
-                resourcesImpl = existingResourcesImpl;
-            } else {
-                // Add this ResourcesImpl to the cache.
-                mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
-            }
-
-            final Resources resources;
-            if (activityToken != null) {
-                resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
-                        resourcesImpl);
-            } else {
-                resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
-            }
-            return resources;
-        }
+        return getOrCreateResources(activityToken, key, classLoader);
     }
 
     /**
@@ -524,34 +636,100 @@
      */
     public void updateResourcesForActivity(@NonNull IBinder activityToken,
             @Nullable Configuration overrideConfig) {
-        final ClassLoader classLoader;
-        final ResourcesKey oldKey;
         synchronized (this) {
-            // Extract the ResourcesKey that was last used to create the Resources for this
-            // activity.
-            WeakReference<Resources> weakResRef = mActivityResourceReferences.get(activityToken);
-            final Resources resources = weakResRef != null ? weakResRef.get() : null;
-            if (resources == null) {
-                Slog.e(TAG, "can't update resources for uncached activity " + activityToken);
+            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                    activityToken);
+
+            if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+                // They are the same, no work to do.
                 return;
             }
 
-            classLoader = resources.getClassLoader();
-            oldKey = findKeyForResourceImpl(resources.getImpl());
-            if (oldKey == null) {
-                Slog.e(TAG, "can't find ResourcesKey for resources impl=" + resources.getImpl());
-                return;
+            // Grab a copy of the old configuration so we can create the delta's of each
+            // Resources object associated with this Activity.
+            final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+
+            // Update the Activity's base override.
+            if (overrideConfig != null) {
+                activityResources.overrideConfig.setTo(overrideConfig);
+            } else {
+                activityResources.overrideConfig.setToDefaults();
+            }
+
+            if (DEBUG) {
+                Throwable here = new Throwable();
+                here.fillInStackTrace();
+                Slog.d(TAG, "updating resources override for activity=" + activityToken
+                        + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
+                        + " to newConfig="
+                        + Configuration.resourceQualifierString(activityResources.overrideConfig),
+                        here);
+            }
+
+            final boolean activityHasOverrideConfig =
+                    !activityResources.overrideConfig.equals(Configuration.EMPTY);
+
+            // Rebase each Resources associated with this Activity.
+            final int refCount = activityResources.activityResources.size();
+            for (int i = 0; i < refCount; i++) {
+                WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
+                Resources resources = weakResRef.get();
+                if (resources == null) {
+                    continue;
+                }
+
+                // Extract the ResourcesKey that was last used to create the Resources for this
+                // activity.
+                final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+                if (oldKey == null) {
+                    Slog.e(TAG, "can't find ResourcesKey for resources impl="
+                            + resources.getImpl());
+                    continue;
+                }
+
+                // Build the new override configuration for this ResourcesKey.
+                final Configuration rebasedOverrideConfig = new Configuration();
+                if (overrideConfig != null) {
+                    rebasedOverrideConfig.setTo(overrideConfig);
+                }
+
+                if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+                    // Generate a delta between the old base Activity override configuration and
+                    // the actual final override configuration that was used to figure out the real
+                    // delta this Resources object wanted.
+                    Configuration overrideOverrideConfig = Configuration.generateDelta(
+                            oldConfig, oldKey.mOverrideConfiguration);
+                    rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+                }
+
+                // Create the new ResourcesKey with the rebased override config.
+                final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
+                        oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+                        rebasedOverrideConfig, oldKey.mCompatInfo);
+
+                if (DEBUG) {
+                    Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+                            + " to newKey=" + newKey);
+                }
+
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+                if (resourcesImpl == null) {
+                    resourcesImpl = createResourcesImpl(newKey);
+                    mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+                }
+
+                if (resourcesImpl != resources.getImpl()) {
+                    // Set the ResourcesImpl, updating it for all users of this Resources object.
+                    resources.setImpl(resourcesImpl);
+                }
             }
         }
-
-        // Update the Resources object with the new override config and all of the existing
-        // settings.
-        getResources(activityToken, oldKey.mResDir, oldKey.mSplitResDirs, oldKey.mOverlayDirs,
-                oldKey.mLibDirs, oldKey.mDisplayId, overrideConfig, oldKey.mCompatInfo,
-                classLoader);
     }
 
     /* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
+        if (mSystemLocales == null) {
+            throw new RuntimeException("ResourcesManager is not ready to negotiate locales.");
+        }
         final int bestLocale;
         if (mHasNonSystemLocales) {
             bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales);
@@ -575,7 +753,7 @@
         int changes = mResConfiguration.updateFrom(config);
         // Things might have changed in display manager, so clear the cached displays.
         mDisplays.clear();
-        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked();
+        DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
 
         if (compat != null && (mResCompatibilityInfo == null ||
                 !mResCompatibilityInfo.equals(compat))) {
@@ -629,7 +807,7 @@
                     }
                     tmpConfig.setTo(localeAdjustedConfig);
                     if (!isDefaultDisplay) {
-                        dm = getDisplayMetricsLocked(displayId);
+                        dm = getDisplayMetrics(displayId);
                         applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
                     }
                     if (hasOverrideConfiguration) {
@@ -649,4 +827,4 @@
 
         return changes != 0;
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2987fbc..bdc4404 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -882,7 +882,12 @@
         public final T getService(ContextImpl ctx) {
             synchronized (StaticApplicationContextServiceFetcher.this) {
                 if (mCachedInstance == null) {
-                    mCachedInstance = createService(ctx.getApplicationContext());
+                    Context appContext = ctx.getApplicationContext();
+                    // If the application context is null, we're either in the system process or
+                    // it's the application context very early in app initialization. In both these
+                    // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
+                    // to the service. http://b/27532714 .
+                    mCachedInstance = createService(appContext != null ? appContext : ctx);
                 }
                 return mCachedInstance;
             }
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 276f774..2c1ee8e 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -36,6 +36,7 @@
 import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
+
 import libcore.io.IoUtils;
 
 import java.io.FileOutputStream;
@@ -77,6 +78,7 @@
 
     private int mOwningUid;
 
+    @Override
     public void connect(IAccessibilityServiceClient client, int flags) {
         if (client == null) {
             throw new IllegalArgumentException("Client cannot be null!");
@@ -326,11 +328,12 @@
             int flags) {
         IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
                 ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
-        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
         info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
         info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
         info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
-                | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
+                | AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
+                | AccessibilityServiceInfo.FLAG_FORCE_DIRECT_BOOT_AWARE;
         info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
                 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
                 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b52af27..72b9318 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -161,8 +161,8 @@
 
     /** @hide */
     @IntDef(flag = true, value = {
-            FLAG_SET_SYSTEM,
-            FLAG_SET_LOCK
+            FLAG_SYSTEM,
+            FLAG_LOCK
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SetWallpaperFlags {}
@@ -170,12 +170,12 @@
     /**
      * Flag: use the supplied imagery as the general system wallpaper.
      */
-    public static final int FLAG_SET_SYSTEM = 1 << 0;
+    public static final int FLAG_SYSTEM = 1 << 0;
 
     /**
      * Flag: use the supplied imagery as the lock-screen wallpaper.
      */
-    public static final int FLAG_SET_LOCK = 1 << 1;
+    public static final int FLAG_LOCK = 1 << 1;
 
     private final Context mContext;
 
@@ -336,7 +336,7 @@
 
             try {
                 Bundle params = new Bundle();
-                ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM,
+                ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SYSTEM,
                         params, userId);
                 if (fd != null) {
                     try {
@@ -663,11 +663,18 @@
 
     /**
      * Get an open, readable file descriptor to the given wallpaper image file.
-     * The callee is resopnsible for closing the fd when done ingesting the file.
+     * The caller is responsible for closing the file descriptor when done ingesting the file.
      *
      * <p>If no lock-specific wallpaper has been configured for the given user, then
-     * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than
+     * this method will return {@code null} when requesting {@link #FLAG_LOCK} rather than
      * returning the system wallpaper's image file.
+     *
+     * @param which The wallpaper whose image file is to be retrieved.  Must be a single
+     *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     *
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      */
     public ParcelFileDescriptor getWallpaperFile(int which) {
         return getWallpaperFile(which, mContext.getUserId());
@@ -677,10 +684,19 @@
      * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
      * for a given user.  The caller must hold the INTERACT_ACROSS_USERS_FULL
      * permission to access another user's wallpaper data.
+     *
+     * @param which The wallpaper whose image file is to be retrieved.  Must be a single
+     *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     * @param userId The user or profile whose imagery is to be retrieved
+     *
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
+     *
      * @hide
      */
     public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
         }
 
@@ -730,8 +746,8 @@
      * such wallpaper configured, returns a negative number.
      *
      * @param which The wallpaper whose ID is to be returned.  Must be a single
-     *     defined kind of wallpaper, either {@link #FLAG_SET_SYSTEM} or
-     *     {@link #FLAG_SET_LOCK}.
+     *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
      * @return The positive numeric ID of the current wallpaper of the given kind,
      *     or a negative value if no such wallpaper is configured.
      */
@@ -823,24 +839,24 @@
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#SET_WALLPAPER}.
      *
-     * @param resid The bitmap to save.
+     * @param resid The resource ID of the bitmap to be used as the wallpaper image
      *
      * @throws IOException If an error occurs reverting to the built-in
      * wallpaper.
      */
     public void setResource(@RawRes int resid) throws IOException {
-        setResource(resid, FLAG_SET_SYSTEM);
+        setResource(resid, FLAG_SYSTEM);
     }
 
     /**
-     * Version of {@link #setResource(int)} that takes an optional Bundle for returning
-     * metadata about the operation to the caller.
+     * Version of {@link #setResource(int)} that allows the caller to specify which
+     * of the supported wallpaper categories to set.
      *
-     * @param resid
-     * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+     * @param resid The resource ID of the bitmap to be used as the wallpaper image
+     * @param which Flags indicating which wallpaper(s) to configure with the new imagery
      *
-     * @see #FLAG_SET_LOCK
-     * @see #FLAG_SET_SYSTEM
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      *
      * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
      *
@@ -934,11 +950,10 @@
      */
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
-        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
     }
 
     /**
-    /**
      * Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
      * to specify which of the supported wallpaper categories to set.
      *
@@ -951,8 +966,8 @@
      *     image for restore to a future device; {@code false} otherwise.
      * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
      *
-     * @see #FLAG_SET_LOCK
-     * @see #FLAG_SET_SYSTEM
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      *
      * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
      *
@@ -1054,7 +1069,7 @@
      */
     public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
-        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
     }
 
     /**
@@ -1070,8 +1085,8 @@
      *     image for restore to a future device; {@code false} otherwise.
      * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
      *
-     * @see #FLAG_SET_LOCK
-     * @see #FLAG_SET_SYSTEM
+     * @see #FLAG_LOCK
+     * @see #FLAG_SYSTEM
      *
      * @throws IOException
      */
@@ -1287,7 +1302,7 @@
      */
     @SystemApi
     public void clearWallpaper() {
-        clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId());
+        clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
     }
 
     /**
@@ -1467,20 +1482,20 @@
 
     /**
      * Remove one or more currently set wallpapers, reverting to the system default
-     * display for each one.  If {@link #FLAG_SET_SYSTEM} is set in the {@code which}
+     * display for each one.  If {@link #FLAG_SYSTEM} is set in the {@code which}
      * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
      * upon success.
      *
-     * @param which A bitwise combination of {@link #FLAG_SET_SYSTEM} or
-     *   {@link #FLAG_SET_LOCK}
+     * @param which A bitwise combination of {@link #FLAG_SYSTEM} or
+     *   {@link #FLAG_LOCK}
      * @throws IOException If an error occurs reverting to the built-in wallpaper.
      */
     public void clear(int which) throws IOException {
-        if ((which & FLAG_SET_SYSTEM) != 0) {
+        if ((which & FLAG_SYSTEM) != 0) {
             clear();
         }
-        if ((which & FLAG_SET_LOCK) != 0) {
-            clearWallpaper(FLAG_SET_LOCK, mContext.getUserId());
+        if ((which & FLAG_LOCK) != 0) {
+            clearWallpaper(FLAG_LOCK, mContext.getUserId());
         }
     }
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 36c82e5..45aa6b4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2655,6 +2655,43 @@
     }
 
     /**
+     * Mark a CA certificate as approved by the device user. This means that they have been notified
+     * of the installation, were made aware of the risks, viewed the certificate and still wanted to
+     * keep the certificate on the device.
+     *
+     * Calling with {@param approval} as {@code true} will cancel any ongoing warnings related to
+     * this certificate.
+     *
+     * @hide
+     */
+    public boolean approveCaCert(String alias, int userHandle, boolean approval) {
+        if (mService != null) {
+            try {
+                return mService.approveCaCert(alias, userHandle, approval);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check whether a CA certificate has been approved by the device user.
+     *
+     * @hide
+     */
+    public boolean isCaCertApproved(String alias, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isCaCertApproved(alias, userHandle);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Installs the given certificate as a user CA.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
@@ -3811,13 +3848,17 @@
      * @return {@code true} if the package is suspended or {@code false} if the package is not
      *         suspended, could not be found or an error occurred.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @throws NameNotFoundException if the package could not be found.
      */
-    public boolean getPackageSuspended(@NonNull ComponentName admin, String packageName) {
+    public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
+            throws NameNotFoundException {
         if (mService != null) {
             try {
-                return mService.getPackageSuspended(admin, packageName);
+                return mService.isPackageSuspended(admin, packageName);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
+            } catch (IllegalArgumentException ex) {
+                throw new NameNotFoundException(packageName);
             }
         }
         return false;
@@ -4889,15 +4930,30 @@
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public Bundle getUserRestrictions(@NonNull ComponentName admin) {
-        return getUserRestrictions(admin, myUserId());
-    }
-
-    /** @hide per-user version */
-    public Bundle getUserRestrictions(@NonNull ComponentName admin, int userHandle) {
         Bundle ret = null;
         if (mService != null) {
             try {
-                ret = mService.getUserRestrictions(admin, userHandle);
+                ret = mService.getUserRestrictions(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return ret == null ? new Bundle() : ret;
+    }
+
+    /**
+     * Called by the system to get the user restrictions for a user.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param userHandle user id the admin is running as.
+     *
+     * @hide
+     */
+    public Bundle getUserRestrictionsForUser(@NonNull ComponentName admin, int userHandle) {
+        Bundle ret = null;
+        if (mService != null) {
+            try {
+                ret = mService.getUserRestrictionsForUser(admin, userHandle);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -5598,10 +5654,9 @@
     }
 
     /**
-     * @hide
      * Return if this user is a managed profile of another user. An admin can become the profile
      * owner of a managed profile with {@link #ACTION_PROVISION_MANAGED_PROFILE} and of a managed
-     * user with {@link #ACTION_PROVISION_MANAGED_USER}.
+     * user with {@link #createAndManageUser}
      * @param admin Which profile owner this request is associated with.
      * @return if this user is a managed profile of another user.
      */
@@ -5905,7 +5960,7 @@
      * <p>
      * <strong> The device logs are retrieved from a RAM region which is not guaranteed to be
      * corruption-free during power cycles, due to hardware variations and limitations. As a result,
-     * this API is provided as best-effort and the returned logs may contain corrupted
+     * this API is provided as best-effort and the returned logs may be empty or contain corrupted
      * data. </strong>
      * <p>
      * There must be only one user on the device, managed by the device owner. Otherwise a
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8be52d8..6ee56aa 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -139,11 +139,13 @@
     CharSequence getDeviceOwnerLockScreenInfo();
 
     String[] setPackagesSuspended(in ComponentName admin, in String[] packageNames, boolean suspended);
-    boolean getPackageSuspended(in ComponentName admin, String packageName);
+    boolean isPackageSuspended(in ComponentName admin, String packageName);
 
     boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
     void uninstallCaCerts(in ComponentName admin, in String[] aliases);
     void enforceCanManageCaCerts(in ComponentName admin);
+    boolean approveCaCert(in String alias, int userHandle, boolean approval);
+    boolean isCaCertApproved(in String alias, int userHandle);
 
     boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer,
             in byte[] certChainBuffer, String alias, boolean requestAccess);
@@ -169,7 +171,8 @@
     ComponentName getRestrictionsProvider(int userHandle);
 
     void setUserRestriction(in ComponentName who, in String key, boolean enable);
-    Bundle getUserRestrictions(in ComponentName who, int userId);
+    Bundle getUserRestrictions(in ComponentName who);
+    Bundle getUserRestrictionsForUser(in ComponentName who, int userId);
     void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
     void clearCrossProfileIntentFilters(in ComponentName admin);
 
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 001a81d..2858991 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -67,7 +67,7 @@
      * information about the process encapsulated in an {@link Object} array, accessible via
      * {@link SecurityEvent#getData()}:
      * process name (String), exact start time (long), app Uid (integer), app Pid (integer),
-     * seinfo tag (String), SHA-256 hash of the APK in hexadecimal (String)
+     * seinfo tag (String), SHA-256 hash of the base APK in hexadecimal (String)
      */
     public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
     /**
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 7d698b3..01f82e6 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -284,6 +284,8 @@
         out.writeInt(mInstance);
         out.writeInt(mProperties);
         out.writeInt(mPermissions);
+        out.writeInt(mKeySize);
+        out.writeInt(mWriteType);
         out.writeTypedList(mDescriptors);
     }
 
@@ -303,6 +305,8 @@
         mInstance = in.readInt();
         mProperties = in.readInt();
         mPermissions = in.readInt();
+        mKeySize = in.readInt();
+        mWriteType = in.readInt();
 
         mDescriptors = new ArrayList<BluetoothGattDescriptor>();
 
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index e355a1c..35437a1 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -144,7 +144,7 @@
     }
 
     /**
-     * 
+     *
      * Get a list of devices that match any of the given connection
      * states.
      *
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 736e55d..eab4c6f 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -40,7 +40,6 @@
         "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
 
     private IBluetoothPbapClient mService;
-    private BluetoothDevice mDevice;
     private final Context mContext;
     private ServiceListener mServiceListener;
     private BluetoothAdapter mAdapter;
@@ -173,7 +172,6 @@
         }
         if (mService != null && isEnabled() && isValidDevice(device)) {
             try {
-                mDevice = device;
                 return mService.connect(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
@@ -193,13 +191,13 @@
      * @return false on error,
      *               true otherwise
      */
-    public boolean disconnect() {
+    public boolean disconnect(BluetoothDevice device) {
         if (DBG) {
-            log("disconnect(" + mDevice + ")");
+            log("disconnect(" + device + ")" + new Exception() );
         }
-        if (mService != null && isEnabled() && isValidDevice(mDevice)) {
+        if (mService != null && isEnabled() && isValidDevice(device)) {
             try {
-                mService.disconnect(mDevice);
+                mService.disconnect(device);
                 return true;
             } catch (RemoteException e) {
               Log.e(TAG, Log.getStackTraceString(new Throwable()));
@@ -328,4 +326,66 @@
        }
        return false;
     }
+
+    /**
+     * Set priority of the profile
+     *
+     * <p> The device should already be paired.
+     *  Priority can be one of {@link #PRIORITY_ON} or
+     * {@link #PRIORITY_OFF},
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) {
+            log("setPriority(" + device + ", " + priority + ")");
+        }
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            if (priority != BluetoothProfile.PRIORITY_OFF &&
+                priority != BluetoothProfile.PRIORITY_ON) {
+              return false;
+            }
+            try {
+                return mService.setPriority(device, priority);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return false;
+    }
+
+    /**
+     * Get the priority of the profile.
+     *
+     * <p> The priority can be any of:
+     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (VDBG) {
+            log("getPriority(" + device + ")");
+        }
+        if (mService != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return mService.getPriority(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return PRIORITY_OFF;
+            }
+        }
+        if (mService == null) {
+            Log.w(TAG, "Proxy not attached to service");
+        }
+        return PRIORITY_OFF;
+    }
 }
diff --git a/core/java/android/bluetooth/IBluetoothPbapClient.aidl b/core/java/android/bluetooth/IBluetoothPbapClient.aidl
index b26ea29..6d4c5a6 100644
--- a/core/java/android/bluetooth/IBluetoothPbapClient.aidl
+++ b/core/java/android/bluetooth/IBluetoothPbapClient.aidl
@@ -29,4 +29,6 @@
     List<BluetoothDevice> getConnectedDevices();
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
     int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b2df207..087ac47 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -164,6 +164,7 @@
         return mBase.getSharedPreferences(name, mode);
     }
 
+    /** @removed */
     @Override
     public SharedPreferences getSharedPreferences(File file, int mode) {
         return mBase.getSharedPreferences(file, mode);
@@ -201,6 +202,7 @@
         return mBase.getFileStreamPath(name);
     }
 
+    /** @removed */
     @Override
     public File getSharedPreferencesPath(String name) {
         return mBase.getSharedPreferencesPath(name);
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 3a17e23..ed5dfa5 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -883,6 +883,15 @@
             return true;
         }
 
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof AuthorityEntry) {
+                final AuthorityEntry other = (AuthorityEntry)obj;
+                return match(other);
+            }
+            return false;
+        }
+
         /**
          * Determine whether this AuthorityEntry matches the given data Uri.
          * <em>Note that this comparison is case-sensitive, unlike formal
@@ -917,7 +926,7 @@
             }
             return MATCH_CATEGORY_HOST;
         }
-    };
+    }
 
     /**
      * Add a new Intent data "scheme specific part" to match against.  The filter must
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index a5617b4..40e1a9f 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -103,53 +103,22 @@
      * @return The drawable associated with the activity.
      */
     public Drawable getIcon(int density) {
-        final int iconRes = mResolveInfo.getIconResource();
-        Drawable icon = getDrawableForDensity(iconRes, density);
-        // Get the default density icon
-        if (icon == null) {
-            icon = mResolveInfo.loadIcon(mPm);
-        }
-        return icon;
-    }
-
-    /**
-     * Returns the icon for this activity, without any badging for the profile.
-     * This function can get the icon no matter the icon needs to be badged or not.
-     * @param density The preferred density of the icon, zero for default density. Use
-     * density DPI values from {@link DisplayMetrics}.
-     * @see #getBadgedIcon(int)
-     * @see DisplayMetrics
-     * @return The drawable associated with the activity.
-     */
-    private Drawable getOriginalIcon(int density) {
         final int iconRes = mResolveInfo.getIconResourceInternal();
-        Drawable icon = getDrawableForDensity(iconRes, density);
-        // Get the default density icon
-        if (icon == null) {
-            icon = mResolveInfo.loadIcon(mPm);
-        }
-        return icon;
-    }
-
-    /**
-     * Returns the drawable for this activity, without any badging for the profile.
-     * @param iconRes id of the drawable.
-     * @param density The preferred density of the icon, zero for default density. Use
-     * density DPI values from {@link DisplayMetrics}.
-     * @see DisplayMetrics
-     * @return The drawable associated with the resource id.
-     */
-    private Drawable getDrawableForDensity(int iconRes, int density) {
+        Drawable icon = null;
         // Get the preferred density icon from the app's resources
         if (density != 0 && iconRes != 0) {
             try {
                 final Resources resources
                         = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
-                return resources.getDrawableForDensity(iconRes, density);
+                icon = resources.getDrawableForDensity(iconRes, density);
             } catch (NameNotFoundException | Resources.NotFoundException exc) {
             }
         }
-        return null;
+        // Get the default density icon
+        if (icon == null) {
+            icon = mResolveInfo.loadIcon(mPm);
+        }
+        return icon;
     }
 
     /**
@@ -201,7 +170,7 @@
      * @return A badged icon for the activity.
      */
     public Drawable getBadgedIcon(int density) {
-        Drawable originalIcon = getOriginalIcon(density);
+        Drawable originalIcon = getIcon(density);
 
         if (originalIcon instanceof BitmapDrawable) {
             return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e89cbd7..39bc783 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -130,6 +130,7 @@
             MATCH_DISABLED_COMPONENTS,
             MATCH_DISABLED_UNTIL_USED_COMPONENTS,
             MATCH_SYSTEM_ONLY,
+            MATCH_FACTORY_ONLY,
             MATCH_DEBUG_TRIAGED_MISSING,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -415,6 +416,13 @@
     public static final int MATCH_SYSTEM_ONLY = 0x00100000;
 
     /**
+     * Internal {@link PackageInfo} flag: include only components on the system image.
+     * This will not return information on any unbundled update to system components.
+     * @hide
+     */
+    public static final int MATCH_FACTORY_ONLY = 0x00200000;
+
+    /**
      * Internal flag used to indicate that a system component has done their
      * homework and verified that they correctly handle packages and components
      * that come and go over time. In particular:
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 984a960..65e0b92 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -113,6 +113,13 @@
     public static final int PROTECTION_FLAG_PREINSTALLED = 0x400;
 
     /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>setup</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     */
+    public static final int PROTECTION_FLAG_SETUP = 0x800;
+
+    /**
      * Mask for {@link #protectionLevel}: the basic protection type.
      */
     public static final int PROTECTION_MASK_BASE = 0xf;
@@ -226,6 +233,9 @@
         if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
             protLevel += "|preinstalled";
         }
+        if ((level&PermissionInfo.PROTECTION_FLAG_SETUP) != 0) {
+            protLevel += "|setup";
+        }
         return protLevel;
     }
 
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7408c34..1812575a 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -34,20 +34,22 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+// TODO Enhance javadoc
 /**
- * TODO Enhance javadoc
  *
- * Represents a shortcut form an application.
+ * Represents a shortcut from an application.
  *
- * Notes...
- * - If an {@link Icon} is of a resource, then we'll just persist the package name and resource ID.
+ * <p>Notes about icons:
+ * <ul>
+ *     <li>If an {@link Icon} is a resource, the system keeps the package name and the resource ID.
+ *     Otherwise, the bitmap is fetched when it's registered to ShortcutManager,
+ *     then shrunk if necessary, and persisted.
+ *     <li>The system disallows byte[] icons, because they can easily go over the binder size limit.
+ * </ul>
  *
- *   Otherwise, the bitmap will be fetched when it's registered to ShortcutManager, then *shrunk*
- *   if necessary, and persisted.
- *
- *   We will disallow byte[] icons, because they can easily go over binder size limit.
+ * @see {@link ShortcutManager}.
  */
-public class ShortcutInfo implements Parcelable {
+public final class ShortcutInfo implements Parcelable {
     /* @hide */
     public static final int FLAG_DYNAMIC = 1 << 0;
 
@@ -371,6 +373,9 @@
 
         /**
          * Sets the title of a shortcut.  This is a mandatory field.
+         *
+         * <p>This field is intended for a concise description of a shortcut displayed under
+         * an icon.  The recommend max length is 10 characters.
          */
         @NonNull
         public Builder setTitle(@NonNull String title) {
@@ -380,6 +385,9 @@
 
         /**
          * Sets the text of a shortcut.  This is an optional field.
+         *
+         * <p>This field is intended to be more descriptive than the shortcut title.
+         * The recommend max length is 25 characters.
          */
         @NonNull
         public Builder setText(@NonNull String text) {
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index b247f65..e4a98b5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -19,15 +19,13 @@
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.List;
 
+// TODO Enhance javadoc
 /**
- * TODO Enhance javadoc
- *
  * {@link ShortcutManager} manages shortcuts created by applications.
  *
  * <h3>Dynamic shortcuts and pinned shortcuts</h3>
@@ -66,15 +64,18 @@
  * {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
  * which happens at a certain time every day.
  *
- * <p>An applications can use {@link #getRateLimitResetTime()} to get the next reset time.
+ * <p>An application can use {@link #getRateLimitResetTime()} to get the next reset time.
+ *
+ * <p>For testing purposes, use "Developer Options" (found in the Settings menu) to reset the
+ * internal rate-limiting counter.  Automated tests can use the following ADB shell command to
+ * achieve the same effect:</p>
+ * <pre>adb shell cmd shortcut reset-throttling</pre>
  *
  * <h3>Backup and Restore</h3>
  *
  * Shortcuts will be backed up and restored across devices.  This means all information, including
  * IDs, must be meaningful on a different device.
  *
- * TODO: Define a Broadcast to let apps update shortcuts on a restored device.
- *
  * <h3>APIs for launcher</h3>
  *
  * Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 63ee8d2..cc82eb6 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -186,7 +186,7 @@
      * @see #TYPE_LINEAR_ACCELERATION
      */
     public static final String STRING_TYPE_LINEAR_ACCELERATION =
-        "android.sensor.linear_acceleration";
+            "android.sensor.linear_acceleration";
 
     /**
      * A constant describing a rotation vector sensor type.
@@ -229,7 +229,7 @@
      * @see #TYPE_AMBIENT_TEMPERATURE
      */
     public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
-        "android.sensor.ambient_temperature";
+            "android.sensor.ambient_temperature";
 
     /**
      * A constant describing an uncalibrated magnetic field sensor type.
@@ -254,7 +254,7 @@
      * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
      */
     public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
-        "android.sensor.magnetic_field_uncalibrated";
+            "android.sensor.magnetic_field_uncalibrated";
 
     /**
      * A constant describing an uncalibrated rotation vector sensor type.
@@ -280,7 +280,7 @@
      * @see #TYPE_GAME_ROTATION_VECTOR
      */
     public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
-        "android.sensor.game_rotation_vector";
+            "android.sensor.game_rotation_vector";
 
     /**
      * A constant describing an uncalibrated gyroscope sensor type.
@@ -302,7 +302,7 @@
      * @see #TYPE_GYROSCOPE_UNCALIBRATED
      */
     public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
-        "android.sensor.gyroscope_uncalibrated";
+            "android.sensor.gyroscope_uncalibrated";
 
     /**
      * A constant describing a significant motion trigger sensor.
@@ -324,7 +324,7 @@
      * @see #TYPE_SIGNIFICANT_MOTION
      */
     public static final String STRING_TYPE_SIGNIFICANT_MOTION =
-        "android.sensor.significant_motion";
+            "android.sensor.significant_motion";
 
     /**
      * A constant describing a step detector sensor.
@@ -391,7 +391,7 @@
      * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
      */
     public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
-        "android.sensor.geomagnetic_rotation_vector";
+            "android.sensor.geomagnetic_rotation_vector";
 
     /**
      * A constant describing a heart rate monitor.
@@ -431,7 +431,7 @@
      * A constant string describing a wake up tilt detector sensor type.
      *
      * @hide
-     * @see #TYPE_WAKE_UP_TILT_DETECTOR
+     * @see #TYPE_TILT_DETECTOR
      */
     public static final String SENSOR_STRING_TYPE_TILT_DETECTOR =
             "android.sensor.tilt_detector";
@@ -495,7 +495,7 @@
      */
     public static final String STRING_TYPE_GLANCE_GESTURE = "android.sensor.glance_gesture";
 
-     /**
+    /**
      * A constant describing a pick up sensor.
      *
      * A sensor of this type triggers when the device is picked up regardless of wherever it was
@@ -514,7 +514,7 @@
      */
     public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
 
-     /**
+    /**
      * A constant describing a wrist tilt gesture sensor.
      *
      * A sensor of this type triggers when the device face is tilted towards the user.
@@ -553,7 +553,7 @@
      */
     public static final String STRING_TYPE_DEVICE_ORIENTATION = "android.sensor.device_orientation";
 
-     /**
+    /**
      * A constant describing a pose sensor with 6 degrees of freedom.
      *
      * Similar to {@link #TYPE_ROTATION_VECTOR}, with additional delta
@@ -578,7 +578,7 @@
      */
     public static final String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
 
-     /**
+    /**
      * A constant describing a stationary detect sensor.
      *
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -593,7 +593,7 @@
      */
     public static final String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
 
-     /**
+    /**
      * A constant describing a motion detect sensor.
      *
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -608,7 +608,7 @@
      */
     public static final String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
 
-     /**
+    /**
      * A constant describing a motion detect sensor.
      *
      * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
@@ -706,6 +706,14 @@
     private static final int DATA_INJECTION_MASK = 0x10;
     private static final int DATA_INJECTION_SHIFT = 4;
 
+    // MASK for dynamic sensor (sensor that added during runtime), bit 6.
+    private static final int DYNAMIC_SENSOR_MASK = 0x20;
+    private static final int DYNAMIC_SENSOR_SHIFT = 5;
+
+    // MASK for indication bit of sensor additional information support (bit 7).
+    private static final int ADDITIONAL_INFO_MASK = 0x40;
+    private static final int ADDITIONAL_INFO_SHIFT = 6;
+
     // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
 
     // Note: This needs to be updated, whenever a new sensor is added.
@@ -887,13 +895,37 @@
     }
 
     /**
-     * @return The type of this sensor as a string.
+     * @return The UUID of the sensor. If the sensor does not support UUID, the returned value will
+     * be an all zero UUID; if the sensor's combination of type and name is guaranteed to be unique
+     * in system, the return value will be an all "F" UUID.
+     *
+     * @hide
      */
+    @SystemApi
     public UUID getUuid() {
         return mUuid;
     }
 
     /**
+     * @return The unique id of sensor. Return value of 0 means this sensor does not support UUID;
+     * return value of -1 means this sensor can be uniquely identified in system by combination of
+     * its type and name.
+     */
+    public int getId() {
+        if (mUuid == ALL_0_UUID) {
+            return 0;
+        } else if (mUuid == ALL_F_UUID) {
+            return -1;
+        } else {
+            int id = Math.abs(mUuid.hashCode()) + 1;
+            if (id <= 0) { // catch corner case when hash is Integer.MIN_VALUE and Integer.MAX_VALUE
+                id = 1;
+            }
+            return id;
+        }
+    }
+
+    /**
      * @hide
      * @return The permission required to access this sensor. If empty, no permission is required.
      */
@@ -961,6 +993,26 @@
     }
 
     /**
+     * Returns true if the sensor is a dynamic sensor.
+     *
+     * @return <code>true</code> if the sensor is a dynamic sensor (sensor added at runtime).
+     * @see SensorManager.DynamicSensorCallback
+     */
+    public boolean isDynamicSensor() {
+        return (mFlags & DYNAMIC_SENSOR_MASK) != 0;
+    }
+
+    /**
+     * Returns true if the sensor supports sensor additional information API
+     *
+     * @return <code>true</code> if the sensor supports sensor additional information API
+     * @see SensorAdditionalInfo
+     */
+    public boolean isAdditionalInfoSupported() {
+        return (mFlags & ADDITIONAL_INFO_MASK) != 0;
+    }
+
+    /**
      * Returns true if the sensor supports data injection when the
      * HAL is set to data injection mode.
      *
@@ -986,6 +1038,10 @@
                 + ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
     }
 
+    //special UUID hash constant
+    private final static UUID ALL_0_UUID = new UUID(0,0);
+    private final static UUID ALL_F_UUID = new UUID(~0L, ~0L);
+
     /**
      * Sets the Type associated with the sensor.
      * NOTE: to be used only by native bindings in SensorManager.
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 8e5b8a3..572a287 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -27,7 +27,7 @@
  * android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
  *
  * @see SensorManager
- * @see SensorEventListener3
+ * @see SensorEventCallback
  * @see Sensor
  *
  */
@@ -106,7 +106,7 @@
      * such as accelerometer, gyro, etc.
      *
      * Payload:
-     *     floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+     *     floatValues[0..11]: First 3 rows of a homogeneous matrix in row major order that captures
      *     any linear transformation, including rotation, scaling, shear, shift.
      */
     public static final int TYPE_VEC3_CALIBRATION = 0x10002;
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 35c96f7..0d96b8e 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -18,7 +18,7 @@
 
 /**
  * This class represents a {@link android.hardware.Sensor Sensor} event and
- * holds informations such as the sensor's type, the time-stamp, accuracy and of
+ * holds information such as the sensor's type, the time-stamp, accuracy and of
  * course the sensor's {@link SensorEvent#values data}.
  *
  * <p>
@@ -163,7 +163,7 @@
      * </ul>
      * <p>
      * Typically the output of the gyroscope is integrated over time to
-     * calculate a rotation describing the change of angles over the timestep,
+     * calculate a rotation describing the change of angles over the time step,
      * for example:
      * </p>
      *
@@ -173,7 +173,7 @@
      *     private float timestamp;
      *
      *     public void onSensorChanged(SensorEvent event) {
-     *          // This timestep's delta rotation to be multiplied by the current rotation
+     *          // This time step's delta rotation to be multiplied by the current rotation
      *          // after computing it from the gyro sample data.
      *          if (timestamp != 0) {
      *              final float dT = (event.timestamp - timestamp) * NS2S;
@@ -192,8 +192,8 @@
      *                  axisZ /= omegaMagnitude;
      *              }
      *
-     *              // Integrate around this axis with the angular speed by the timestep
-     *              // in order to get a delta rotation from this sample over the timestep
+     *              // Integrate around this axis with the angular speed by the time step
+     *              // in order to get a delta rotation from this sample over the time step
      *              // We will convert this axis-angle representation of the delta rotation
      *              // into a quaternion before turning it into the rotation matrix.
      *              float thetaOverTwo = omegaMagnitude * dT / 2.0f;
@@ -433,9 +433,9 @@
      * Each field is a component of the estimated hard iron calibration.
      * The values are in micro-Tesla (uT).
      * </p>
-     * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanenet
+     * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanent
      * magnets on the device.
-     * Soft iron - These distortions arise due to the interaction with the earth's magentic
+     * Soft iron - These distortions arise due to the interaction with the earth's magnetic
      * field.
      * </p>
      * <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}:</h4>
@@ -508,14 +508,14 @@
      *
      *
      * <ul>
-     *  <li> values[0]: x*sin(&#952/2) </li>
-     *  <li> values[1]: y*sin(&#952/2) </li>
-     *  <li> values[2]: z*sin(&#952/2) </li>
-     *  <li> values[3]: cos(&#952/2)   </li>
+     * <li> values[0]: x*sin(&#952/2) </li>
+     * <li> values[1]: y*sin(&#952/2) </li>
+     * <li> values[2]: z*sin(&#952/2) </li>
+     * <li> values[3]: cos(&#952/2)   </li>
      *
      *
      * <li> values[4]: Translation along x axis from an arbitrary origin. </li>
-     * li> values[5]: Translation along y axis from an arbitrary origin. </li>
+     * <li> values[5]: Translation along y axis from an arbitrary origin. </li>
      * <li> values[6]: Translation along z axis from an arbitrary origin. </li>
      *
      * <li> values[7]:  Delta quaternion rotation x*sin(&#952/2) </li>
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 5684aa5..a20307a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -884,7 +884,7 @@
      * Used for receiving notifications from the SensorManager when dynamic sensors are connected or
      * disconnected.
      */
-    public static abstract class DynamicSensorConnectionCallback {
+    public static abstract class DynamicSensorCallback {
         /**
          * Called when there is a dynamic sensor being connected to the system.
          *
@@ -902,62 +902,73 @@
 
 
     /**
-     * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+     * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+     * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
      * registration with the already registered callback object will have no additional effect.
      *
      * @param callback An object that implements the
-     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     *        DynamicSensorConnectionCallback}
+     *        {@link android.hardware.SensorManager.DynamicSensorCallback
+     *        DynamicSensorCallback}
      *        interface for receiving callbacks.
-     * @see #addDynamicSensorCallback(DynamicSensorConnectionCallback, Handler)
+     * @see #addDynamicSensorCallback(DynamicSensorCallback, Handler)
      *
      * @throws IllegalArgumentException when callback is null.
      */
-    public void registerDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+    public void registerDynamicSensorCallback(DynamicSensorCallback callback) {
         registerDynamicSensorCallback(callback, null);
     }
 
     /**
-     * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     * DynamicSensorConnectionCallback} to receive dynamic sensor connection callbacks. Repeat
+     * Add a {@link android.hardware.SensorManager.DynamicSensorCallback
+     * DynamicSensorCallback} to receive dynamic sensor connection callbacks. Repeat
      * registration with the already registered callback object will have no additional effect.
      *
      * @param callback An object that implements the
-     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     *        DynamicSensorConnectionCallback} interface for receiving callbacks.
+     *        {@link android.hardware.SensorManager.DynamicSensorCallback
+     *        DynamicSensorCallback} interface for receiving callbacks.
      * @param handler The {@link android.os.Handler Handler} the {@link
-     *        android.hardware.SensorManager.DynamicSensorConnectionCallback
+     *        android.hardware.SensorManager.DynamicSensorCallback
      *        sensor connection events} will be delivered to.
      *
      * @throws IllegalArgumentException when callback is null.
      */
     public void registerDynamicSensorCallback(
-            DynamicSensorConnectionCallback callback, Handler handler) {
+            DynamicSensorCallback callback, Handler handler) {
         registerDynamicSensorCallbackImpl(callback, handler);
     }
 
     /**
-     * Remove a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     * DynamicSensorConnectionCallback} to stop sending dynamic sensor connection events to that
+     * Remove a {@link android.hardware.SensorManager.DynamicSensorCallback
+     * DynamicSensorCallback} to stop sending dynamic sensor connection events to that
      * callback.
      *
      * @param callback An object that implements the
-     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
-     *        DynamicSensorConnectionCallback}
+     *        {@link android.hardware.SensorManager.DynamicSensorCallback
+     *        DynamicSensorCallback}
      *        interface for receiving callbacks.
      */
-    public void unregisterDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+    public void unregisterDynamicSensorCallback(DynamicSensorCallback callback) {
         unregisterDynamicSensorCallbackImpl(callback);
     }
 
+    /**
+     * Tell if dynamic sensor discovery feature is supported by system.
+     *
+     * @return <code>true</code> if dynamic sensor discovery is supported, <code>false</code>
+     * otherwise.
+     */
+    public boolean isDynamicSensorDiscoverySupported() {
+        List<Sensor> sensors = getSensorList(Sensor.TYPE_DYNAMIC_SENSOR_META);
+        return sensors.size() > 0;
+    }
+
     /** @hide */
     protected abstract void registerDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback, Handler handler);
+            DynamicSensorCallback callback, Handler handler);
 
     /** @hide */
     protected abstract void unregisterDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback);
+            DynamicSensorCallback callback);
 
     /**
      * <p>
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7d903bd..259ca03 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -1,4 +1,4 @@
-    /*
+/*
  * Copyright (C) 2012 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -76,7 +76,7 @@
             new HashMap<TriggerEventListener, TriggerEventQueue>();
 
     // Dynamic Sensor callbacks
-    private HashMap<DynamicSensorConnectionCallback, Handler>
+    private HashMap<DynamicSensorCallback, Handler>
             mDynamicSensorCallbacks = new HashMap<>();
     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
 
@@ -120,7 +120,7 @@
     @Override
     protected List<Sensor> getFullDynamicSensorList() {
         // only set up broadcast receiver if the application tries to find dynamic sensors or
-        // explicitly register a DynamicSensorConnectionCallback
+        // explicitly register a DynamicSensorCallback
         setupDynamicSensorBroadcastReceiver();
         updateDynamicSensorList();
         return mFullDynamicSensorsList;
@@ -354,9 +354,9 @@
 
                     Handler mainHandler = new Handler(mContext.getMainLooper());
 
-                    for (Map.Entry<DynamicSensorConnectionCallback, Handler> entry :
+                    for (Map.Entry<DynamicSensorCallback, Handler> entry :
                             mDynamicSensorCallbacks.entrySet()) {
-                        final DynamicSensorConnectionCallback callback = entry.getKey();
+                        final DynamicSensorCallback callback = entry.getKey();
                         Handler handler =
                                 entry.getValue() == null ? mainHandler : entry.getValue();
 
@@ -413,7 +413,7 @@
 
     /** @hide */
     protected void registerDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback, Handler handler) {
+            DynamicSensorCallback callback, Handler handler) {
         if (DEBUG_DYNAMIC_SENSOR) {
             Log.i(TAG, "DYNS Register dynamic sensor callback");
         }
@@ -432,7 +432,7 @@
 
     /** @hide */
     protected void unregisterDynamicSensorCallbackImpl(
-            DynamicSensorConnectionCallback callback) {
+            DynamicSensorCallback callback) {
         if (DEBUG_DYNAMIC_SENSOR) {
             Log.i(TAG, "Removing dynamic sensor listerner");
         }
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4add962..d06e08b 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2025,11 +2025,20 @@
      * produced in response to a capture request submitted
      * while in HDR mode.</p>
      * <p>Since substantial post-processing is generally needed to
-     * produce an HDR image, only YUV and JPEG outputs are
-     * supported for LIMITED/FULL device HDR captures, and only
-     * JPEG outputs are supported for LEGACY HDR
-     * captures. Using a RAW output for HDR capture is not
+     * produce an HDR image, only YUV, PRIVATE, and JPEG
+     * outputs are supported for LIMITED/FULL device HDR
+     * captures, and only JPEG outputs are supported for LEGACY
+     * HDR captures. Using a RAW output for HDR capture is not
      * supported.</p>
+     * <p>Some devices may also support always-on HDR, which
+     * applies HDR processing at full frame rate.  For these
+     * devices, intents other than STILL_CAPTURE will also
+     * produce an HDR output with no frame rate impact compared
+     * to normal operation, though the quality may be lower
+     * than for STILL_CAPTURE intents.</p>
+     * <p>If SCENE_MODE_HDR is used with unsupported output types
+     * or capture intents, the images captured will be as if
+     * the SCENE_MODE was not enabled at all.</p>
      *
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      * @see CaptureRequest#CONTROL_SCENE_MODE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 5748726..4f41e1c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3373,7 +3373,7 @@
 
     /**
      * <p>Maximum raw value output by sensor for this frame.</p>
-     * <p>Since the android.sensor.blackLevel may change for different
+     * <p>Since the {@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern} may change for different
      * capture settings (e.g., {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}), the white
      * level will change accordingly. This key is similar to
      * {@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}, but specifies the camera device
@@ -3385,6 +3385,7 @@
      * &gt;= 0</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
      * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
      * @see CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS
      * @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 2c2ad1c..b0b94e3 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -70,7 +70,7 @@
      * CameraDeviceStateListener callbacks to be called after state transitions.
      */
     public interface CameraDeviceStateListener {
-        void onError(int errorCode, RequestHolder holder);
+        void onError(int errorCode, Object errorArg, RequestHolder holder);
         void onConfiguring();
         void onIdle();
         void onBusy();
@@ -162,11 +162,12 @@
      * @param captureError Report a recoverable error for a single buffer or result using a valid
      *                     error code for {@code ICameraDeviceCallbacks}, or
      *                     {@link #NO_CAPTURE_ERROR}.
+     * @param captureErrorArg An argument for some error captureError codes.
      * @return {@code false} if an error has occurred.
      */
     public synchronized boolean setCaptureResult(final RequestHolder request,
-                                             final CameraMetadataNative result,
-                                             final int captureError) {
+            final CameraMetadataNative result,
+            final int captureError, final Object captureErrorArg) {
         if (mCurrentState != STATE_CAPTURING) {
             Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
             mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
@@ -179,7 +180,7 @@
                 mCurrentHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        mCurrentListener.onError(captureError, request);
+                        mCurrentListener.onError(captureError, captureErrorArg, request);
                     }
                 });
             } else {
@@ -194,6 +195,11 @@
         return mCurrentError == NO_CAPTURE_ERROR;
     }
 
+    public synchronized boolean setCaptureResult(final RequestHolder request,
+            final CameraMetadataNative result) {
+        return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
+    }
+
     /**
      * Set the listener for state transition callbacks.
      *
@@ -239,7 +245,7 @@
                     mCurrentHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            mCurrentListener.onError(mCurrentError, mCurrentRequest);
+                            mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
                         }
                     });
                 }
@@ -299,7 +305,7 @@
                         mCurrentHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                mCurrentListener.onError(error, mCurrentRequest);
+                                mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
                             }
                         });
                     } else {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index d01c275..f99928a 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -480,19 +480,15 @@
             throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
-        ArrayList<Surface> surfaces = null;
+        SparseArray<Surface> surfaces = null;
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
                 String err = "Cannot end configure, no configuration change in progress.";
                 Log.e(TAG, err);
                 throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
-            int numSurfaces = mSurfaces.size();
-            if (numSurfaces > 0) {
-                surfaces = new ArrayList<>();
-                for (int i = 0; i < numSurfaces; ++i) {
-                    surfaces.add(mSurfaces.valueAt(i));
-                }
+            if (mSurfaces != null) {
+                surfaces = mSurfaces.clone();
             }
             mConfiguring = false;
         }
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
index eb48a01..113927c 100644
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
@@ -19,7 +19,7 @@
 import android.util.Log;
 import android.util.MutableLong;
 import android.util.Pair;
-
+import android.view.Surface;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.TreeSet;
@@ -95,22 +95,28 @@
                     } else {
                         // Send buffer dropped errors for each pending buffer if the request has
                         // started.
-                        if (mFailedPreview) {
-                            Log.w(TAG, "Preview buffers dropped for request: " +
-                                    mRequest.getRequestId());
-                            for (int i = 0; i < mRequest.numPreviewTargets(); i++) {
-                                CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
-                                    /*result*/null,
-                                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
-                            }
-                        }
-                        if (mFailedJpeg) {
-                            Log.w(TAG, "Jpeg buffers dropped for request: " +
-                                    mRequest.getRequestId());
-                            for (int i = 0; i < mRequest.numJpegTargets(); i++) {
-                                CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
-                                    /*result*/null,
-                                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER);
+                        for (Surface targetSurface : mRequest.getRequest().getTargets() ) {
+                            try {
+                                if (mRequest.jpegType(targetSurface)) {
+                                    if (mFailedJpeg) {
+                                        CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+                                                /*result*/null,
+                                                CameraDeviceImpl.CameraDeviceCallbacks.
+                                                        ERROR_CAMERA_BUFFER,
+                                                targetSurface);
+                                    }
+                                } else {
+                                    // preview buffer
+                                    if (mFailedPreview) {
+                                        CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
+                                                /*result*/null,
+                                                CameraDeviceImpl.CameraDeviceCallbacks.
+                                                        ERROR_CAMERA_BUFFER,
+                                                targetSurface);
+                                    }
+                                }
+                            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                                Log.e(TAG, "Unexpected exception when querying Surface: " + e);
                             }
                         }
                     }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 661edd7..6c95869 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Size;
+import android.util.SparseArray;
 import android.view.Surface;
 
 import java.util.ArrayList;
@@ -64,7 +65,7 @@
     private final CameraCharacteristics mStaticCharacteristics;
     private final ICameraDeviceCallbacks mDeviceCallbacks;
     private final CameraDeviceState mDeviceState = new CameraDeviceState();
-    private List<Surface> mConfiguredSurfaces;
+    private SparseArray<Surface> mConfiguredSurfaces;
     private boolean mClosed = false;
 
     private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
@@ -89,13 +90,29 @@
     public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
 
     private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
+        return getExtrasFromRequest(holder,
+                /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
+    }
+
+    private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
+            int errorCode, Object errorArg) {
+        int errorStreamId = -1;
+        if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
+            Surface errorTarget = (Surface) errorArg;
+            int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
+            if (indexOfTarget < 0) {
+                Log.e(TAG, "Buffer drop error reported for unknown Surface");
+            } else {
+                errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
+            }
+        }
         if (holder == null) {
             return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
                     ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
         }
         return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
                 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
-                /*partialResultCount*/1, /*errorStreamId*/-1);
+                /*partialResultCount*/1, errorStreamId);
     }
 
     /**
@@ -105,9 +122,9 @@
     private final CameraDeviceState.CameraDeviceStateListener mStateListener =
             new CameraDeviceState.CameraDeviceStateListener() {
         @Override
-        public void onError(final int errorCode, final RequestHolder holder) {
+        public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
             if (DEBUG) {
-                Log.d(TAG, "onError called, errorCode = " + errorCode);
+                Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
             }
             switch (errorCode) {
                 /*
@@ -125,7 +142,7 @@
                 }
             }
 
-            final CaptureResultExtras extras = getExtrasFromRequest(holder);
+            final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
             mResultHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -281,14 +298,17 @@
      *
      * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
      *
-     * @param outputs a list of surfaces to set.
+     * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
+     *          list; it must not be modified by the caller once it's passed in.
      * @return an error code for this binder operation, or {@link NO_ERROR}
      *          on success.
      */
-    public int configureOutputs(List<Surface> outputs) {
+    public int configureOutputs(SparseArray<Surface> outputs) {
         List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
         if (outputs != null) {
-            for (Surface output : outputs) {
+            int count = outputs.size();
+            for (int i = 0; i < count; i++)  {
+                Surface output = outputs.valueAt(i);
                 if (output == null) {
                     Log.e(TAG, "configureOutputs - null outputs are not allowed");
                     return BAD_VALUE;
@@ -353,7 +373,7 @@
         }
 
         if (success) {
-            mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
+            mConfiguredSurfaces = outputs;
         } else {
             return LegacyExceptionUtils.INVALID_OPERATION;
         }
@@ -659,6 +679,23 @@
         return nativeGetSurfaceId(surface);
     }
 
+    static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
+        if (surfaces == null) {
+            throw new NullPointerException("Null argument surfaces");
+        }
+        List<Long> surfaceIds = new ArrayList<>();
+        int count = surfaces.size();
+        for (int i = 0; i < count; i++) {
+            long id = getSurfaceId(surfaces.valueAt(i));
+            if (id == 0) {
+                throw new IllegalStateException(
+                        "Configured surface had null native GraphicBufferProducer pointer!");
+            }
+            surfaceIds.add(id);
+        }
+        return surfaceIds;
+    }
+
     static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
         if (surfaces == null) {
             throw new NullPointerException("Null argument surfaces");
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index 9b628fb..476c3de 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -41,6 +41,8 @@
     private final int mNumPreviewTargets;
     private volatile boolean mFailed = false;
 
+    private final Collection<Long> mJpegSurfaceIds;
+
     /**
      * A builder class for {@link RequestHolder} objects.
      *
@@ -150,13 +152,13 @@
          */
         public RequestHolder build(long frameNumber) {
             return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
-                    mNumJpegTargets, mNumPreviewTargets);
+                    mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
         }
     }
 
     private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
                           boolean repeating, long frameNumber, int numJpegTargets,
-                          int numPreviewTargets) {
+                          int numPreviewTargets, Collection<Long> jpegSurfaceIds) {
         mRepeating = repeating;
         mRequest = request;
         mRequestId = requestId;
@@ -164,6 +166,7 @@
         mFrameNumber = frameNumber;
         mNumJpegTargets = numJpegTargets;
         mNumPreviewTargets = numPreviewTargets;
+        mJpegSurfaceIds = jpegSurfaceIds;
     }
 
     /**
@@ -238,6 +241,17 @@
     }
 
     /**
+     * Returns true if the given surface requires jpeg buffers.
+     *
+     * @param s a {@link android.view.Surface} to check.
+     * @return true if the surface requires a jpeg buffer.
+     */
+    public boolean jpegType(Surface s)
+            throws LegacyExceptionUtils.BufferQueueAbandonedException {
+        return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
+    }
+
+    /**
      * Mark this request as failed.
      */
     public void failRequest() {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e8ce3ec..a3fdd56 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -908,8 +908,7 @@
                         mFaceDetectMapper.mapResultFaces(result, mLastRequest);
 
                         if (!holder.requestFailed()) {
-                            mDeviceState.setCaptureResult(holder, result,
-                                    CameraDeviceState.NO_CAPTURE_ERROR);
+                            mDeviceState.setCaptureResult(holder, result);
                         }
                     }
                     if (DEBUG) {
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 644e29f..ae44f1d 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -37,6 +37,7 @@
     private float mStoppedPowerDrawMw;
     private float mSleepPowerDrawMw;
     private float mPeakPowerDrawMw;
+    private int mMaxPacketLengthBytes;
 
     private int[] mSupportedSensors;
 
@@ -46,6 +47,27 @@
     }
 
     /**
+     * returns the maximum number of bytes that can be sent per message to the hub
+     *
+     * @return int - maximum bytes that can be transmitted in a
+     *         single packet
+     */
+    public int getMaxPacketLengthBytes() {
+        return mMaxPacketLengthBytes;
+    }
+
+    /**
+     * set the context hub unique identifer
+     *
+     * @param bytes - Maximum number of bytes per message
+     *
+     * @hide
+     */
+    public void setMaxPacketLenBytes(int bytes) {
+        mMaxPacketLengthBytes = bytes;
+    }
+
+    /**
      * get the context hub unique identifer
      *
      * @return int - unique system wide identifier
@@ -374,4 +396,4 @@
             return new ContextHubInfo[size];
         }
     };
-}
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 4ddf767..89edaa9 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -43,23 +43,6 @@
     private Handler mCallbackHandler;
 
     /**
-     * A special context hub identifier meaning any possible hub on the system.
-     */
-    public static final int ANY_HUB       = -1;
-    /**
-     * A constant denoting a message to load a a Nano App
-     */
-    public static final int MSG_LOAD_NANO_APP   = 1;
-    /**
-     * A constant denoting a message to unload a a Nano App
-     */
-    public static final int MSG_UNLOAD_NANO_APP = 2;
-    /**
-     * A constant denoting a message to send a message
-     */
-    public static final int MSG_DATA_SEND       = 3;
-
-    /**
      * An interface to receive asynchronous communication from the context hub.
      */
     public abstract static class Callback {
@@ -69,7 +52,7 @@
          * Callback function called on message receipt from context hub.
          *
          * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
-         * @param nanoAppHandle Handle (unique identifier) for the app that sent the message.
+         * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
          * @param message The context hub message.
          *
          * @see ContextHubMessage
@@ -89,7 +72,7 @@
         try {
             retVal = getBinder().getContextHubHandles();
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch context hub handles : " + e);
+            Log.w(TAG, "Could not fetch context hub handles : " + e);
         }
         return retVal;
     }
@@ -107,7 +90,7 @@
         try {
             retVal = getBinder().getContextHubInfo(hubHandle);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch context hub info :" + e);
+            Log.w(TAG, "Could not fetch context hub info :" + e);
         }
 
         return retVal;
@@ -126,6 +109,7 @@
      */
     public int loadNanoApp(int hubHandle, NanoApp app) {
         int retVal = -1;
+
         if (app == null) {
             return retVal;
         }
@@ -133,7 +117,7 @@
         try {
             retVal = getBinder().loadNanoApp(hubHandle, app);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch load nanoApp :" + e);
+            Log.w(TAG, "Could not load nanoApp :" + e);
         }
 
         return retVal;
@@ -152,7 +136,7 @@
         try {
             retVal = getBinder().unloadNanoApp(nanoAppHandle);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch unload nanoApp :" + e);
+            Log.w(TAG, "Could not fetch unload nanoApp :" + e);
         }
 
         return retVal;
@@ -172,7 +156,7 @@
         try {
             retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch nanoApp info :" + e);
+            Log.w(TAG, "Could not fetch nanoApp info :" + e);
         }
 
         return retVal;
@@ -193,7 +177,7 @@
         try {
             retVal = getBinder().findNanoAppOnHub(hubHandle, filter);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not query nanoApp instance :" + e);
+            Log.w(TAG, "Could not query nanoApp instance :" + e);
         }
         return retVal;
     }
@@ -212,10 +196,14 @@
     public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) {
         int retVal = -1;
 
+        if (message == null || message.getData() == null) {
+            Log.w(TAG, "null ptr");
+            return retVal;
+        }
         try {
             retVal = getBinder().sendMessage(hubHandle, nanoAppHandle, message);
         } catch (RemoteException e) {
-            Log.e(TAG, "Could not fetch send message :" + e.toString());
+            Log.w(TAG, "Could not send message :" + e.toString());
         }
 
         return retVal;
@@ -247,7 +235,7 @@
     public int registerCallback(Callback callback, Handler handler) {
         synchronized(this) {
             if (mCallback != null) {
-                Log.e(TAG, "Max number of callbacks reached!");
+                Log.w(TAG, "Max number of callbacks reached!");
                 return -1;
             }
             mCallback = callback;
@@ -268,7 +256,7 @@
     public int unregisterCallback(Callback callback) {
       synchronized(this) {
           if (callback != mCallback) {
-              Log.e(TAG, "Cannot recognize callback!");
+              Log.w(TAG, "Cannot recognize callback!");
               return -1;
           }
 
@@ -311,11 +299,11 @@
             try {
                 getBinder().registerCallback(mClientCallback);
             } catch (RemoteException e) {
-                Log.e(TAG, "Could not register callback:" + e);
+                Log.w(TAG, "Could not register callback:" + e);
             }
 
         } else {
-            Log.d(TAG, "failed to getService");
+            Log.w(TAG, "failed to getService");
         }
     }
 
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index 954e97d..bca2ae6 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -16,10 +16,10 @@
 
 package android.hardware.location;
 
-
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 import java.util.Arrays;
 
@@ -32,6 +32,9 @@
     private int mVersion;
     private byte[]mData;
 
+    private static final String TAG = "ContextHubMessage";
+
+
     /**
      * Get the message type
      *
@@ -106,9 +109,11 @@
     private ContextHubMessage(Parcel in) {
         mType = in.readInt();
         mVersion = in.readInt();
-        byte[] byteBuffer = new byte[in.readInt()];
-        in.readByteArray(byteBuffer);
+        int bufferLength = in.readInt();
+        mData = new byte[bufferLength];
+        in.readByteArray(mData);
     }
+
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mType);
         out.writeInt(mVersion);
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 274babe..b65e24e 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -29,12 +29,30 @@
  */
 public class ContextHubService extends IContextHubService.Stub {
 
+    public static final String CONTEXTHUB_SERVICE = "contexthub_service";
+
     private static final String TAG = "ContextHubService";
     private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
     private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
             + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
 
-    public static final String CONTEXTHUB_SERVICE = "contexthub_service";
+
+    public static final int ANY_HUB             = -1;
+    public static final int MSG_LOAD_NANO_APP   = 5;
+    public static final int MSG_UNLOAD_NANO_APP = 2;
+
+    private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
+    private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
+    private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
+    private static final int PRE_LOADED_APP_MEM_REQ = 0;
+
+    private static final int MSG_HEADER_SIZE = 4;
+    private static final int MSG_FIELD_TYPE = 0;
+    private static final int MSG_FIELD_VERSION = 1;
+    private static final int MSG_FIELD_HUB_HANDLE = 2;
+    private static final int MSG_FIELD_APP_INSTANCE = 3;
+
+    private static final int OS_APP_INSTANCE = -1;
 
     private final Context mContext;
 
@@ -42,44 +60,27 @@
     private ContextHubInfo[] mContextHubInfo;
     private IContextHubCallback mCallback;
 
+    private native int nativeSendMessage(int[] header, byte[] data);
+    private native ContextHubInfo[] nativeInitialize();
+
+
     public ContextHubService(Context context) {
         mContext = context;
         mContextHubInfo = nativeInitialize();
+        mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
 
         for (int i = 0; i < mContextHubInfo.length; i++) {
-            Log.v(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+            Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
                   + ", name:  " + mContextHubInfo[i].getName());
         }
     }
 
-    private native int nativeSendMessage(int[] header, byte[] data);
-    private native ContextHubInfo[] nativeInitialize();
-
     @Override
-    public int registerCallback(IContextHubCallback callback) throws RemoteException{
+    public int registerCallback(IContextHubCallback callback) throws RemoteException {
         checkPermissions();
-        mCallback = callback;
-        return 0;
-    }
-
-
-    private int onMessageReceipt(int[] header, byte[] data) {
-        if (mCallback != null) {
-            // TODO : Defend against unexpected header sizes
-            //        Add abstraction for magic numbers
-            //        onMessageRecipt should pass the right arguments
-            ContextHubMessage msg = new ContextHubMessage(header[0], header[1], data);
-
-            try {
-                mCallback.onMessageReceipt(0, 0, msg);
-            } catch (Exception e) {
-                Log.e(TAG, "Exception " + e + " when calling remote callback");
-                return -1;
-            }
-        } else {
-            Log.d(TAG, "Message Callback is NULL");
+        synchronized(this) {
+          mCallback = callback;
         }
-
         return 0;
     }
 
@@ -118,14 +119,17 @@
         }
 
         // Call Native interface here
-        int[] msgHeader = new int[8];
-        msgHeader[0] = contextHubHandle;
-        msgHeader[1] = app.getAppId();
-        msgHeader[2] = app.getAppVersion();
-        msgHeader[3] = ContextHubManager.MSG_LOAD_NANO_APP;
-        msgHeader[4] = 0; // Loading hints
+        int[] msgHeader = new int[MSG_HEADER_SIZE];
+        msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
+        msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+        msgHeader[MSG_FIELD_VERSION] = 0;
+        msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
 
-        return nativeSendMessage(msgHeader, app.getAppBinary());
+        if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
+            return -1;
+        }
+        // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+        return 0;
     }
 
     @Override
@@ -137,12 +141,18 @@
         }
 
         // Call Native interface here
-        int[] msgHeader = new int[8];
-        msgHeader[0] = info.getContexthubId();
-        msgHeader[1] = ContextHubManager.MSG_UNLOAD_NANO_APP;
-        msgHeader[2] = info.getHandle();
+        int[] msgHeader = new int[MSG_HEADER_SIZE];
+        msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
+        msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+        msgHeader[MSG_FIELD_VERSION] = 0;
+        msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
 
-        return nativeSendMessage(msgHeader, null);
+        if(nativeSendMessage(msgHeader, null) != 0) {
+            return -1;
+        }
+
+        // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
+        return 0;
     }
 
     @Override
@@ -166,7 +176,7 @@
         for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
             NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
 
-            if(filter.testMatch(info)){
+            if (filter.testMatch(info)){
                 foundInstances.add(nanoAppInstance);
             }
         }
@@ -183,12 +193,12 @@
     public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
             throws RemoteException {
         checkPermissions();
-        int[] msgHeader = new int[8];
-        msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
-        msgHeader[1] = hubHandle;
-        msgHeader[2] = nanoAppHandle;
-        msgHeader[3] = msg.getMsgType();
-        msgHeader[4] = msg.getVersion();
+
+        int[] msgHeader = new int[MSG_HEADER_SIZE];
+        msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
+        msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
+        msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
+        msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
 
         return nativeSendMessage(msgHeader, msg.getData());
     }
@@ -196,5 +206,52 @@
     private void checkPermissions() {
         mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
     }
-}
 
+    private int onMessageReceipt(int[] header, byte[] data) {
+        if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
+            return  -1;
+        }
+
+        synchronized(this) {
+            if (mCallback != null) {
+                ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
+                        header[MSG_FIELD_VERSION],
+                        data);
+
+                try {
+                    mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
+                            header[MSG_FIELD_APP_INSTANCE],
+                            msg);
+                } catch (Exception e) {
+                    Log.w(TAG, "Exception " + e + " when calling remote callback");
+                    return -1;
+                }
+            } else {
+                Log.d(TAG, "Message Callback is NULL");
+            }
+        }
+
+        return 0;
+    }
+
+    private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
+        // App Id encodes vendor & version
+        NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
+
+        appInfo.setAppId(appId);
+        appInfo.setAppVersion(appVersion);
+        appInfo.setName(PRE_LOADED_APP_NAME);
+        appInfo.setContexthubId(hubHandle);
+        appInfo.setHandle(appInstanceHandle);
+        appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
+        appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
+        appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
+        appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
+
+        mNanoAppHash.put(appInstanceHandle, appInfo);
+        Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
+              + " version " + appVersion);
+
+        return 0;
+    }
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 369f9e4..8db70e9 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 /**
  * @hide
@@ -27,6 +28,8 @@
 @SystemApi
 public class NanoAppFilter {
 
+    private static final String TAG = "NanoAppFilter";
+
     // The appId, can be set to APP_ID_ANY
     private long mAppId;
 
@@ -54,6 +57,10 @@
      * If this flag is set, only versions strictly less than the version specified shall match.
      */
     public static final int FLAGS_VERSION_LESS_THAN   = 4;
+    /**
+     * If this flag is set, only versions strictly equal to the
+     * version specified shall match.
+     */
     public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
 
     /**
@@ -117,14 +124,9 @@
      * @return true if this is a match, false otherwise
      */
     public boolean testMatch(NanoAppInstanceInfo info) {
-        if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
+        return (mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) &&
                 (mAppId == APP_ANY || info.getAppId() == mAppId) &&
-               // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
-                (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
-            return true;
-        } else {
-            return false;
-        }
+                (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
     }
 
     public static final Parcelable.Creator<NanoAppFilter> CREATOR
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index ac62919..977f645 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -29,7 +29,7 @@
     private String mPublisher;
     private String mName;
 
-    private int mAppId;
+    private long mAppId;
     private int mAppVersion;
 
     private int mNeededReadMemBytes;
@@ -59,6 +59,8 @@
      * set the publisher name for the app
      *
      * @param publisher - name of the publisher
+     *
+     * @hide
      */
     public void setPublisher(String publisher) {
         mPublisher = publisher;
@@ -77,6 +79,8 @@
      * set the name of the app
      *
      * @param name - name of the app
+     *
+     * @hide
      */
     public void setName(String name) {
         mName = name;
@@ -87,7 +91,7 @@
      *
      * @return int - application identifier
      */
-    public int getAppId() {
+    public long getAppId() {
         return mAppId;
     }
 
@@ -95,8 +99,10 @@
      * Set the application identifier
      *
      * @param appId - application identifier
+     *
+     * @hide
      */
-    public void setAppId(int appId) {
+    public void setAppId(long appId) {
         mAppId = appId;
     }
 
@@ -113,6 +119,8 @@
      * Set the application version
      *
      * @param appVersion - version of the app
+     *
+     * @hide
      */
     public void setAppVersion(int appVersion) {
         mAppVersion = appVersion;
@@ -131,6 +139,8 @@
      * Set the read memory needed by the app
      *
      * @param neededReadMemBytes - readable Memory needed in bytes
+     *
+     * @hide
      */
     public void setNeededReadMemBytes(int neededReadMemBytes) {
         mNeededReadMemBytes = neededReadMemBytes;
@@ -150,6 +160,8 @@
      *
      * @param neededWriteMemBytes - writable memory needed by the
      *                            app
+     *
+     * @hide
      */
     public void setNeededWriteMemBytes(int neededWriteMemBytes) {
         mNeededWriteMemBytes = neededWriteMemBytes;
@@ -169,6 +181,8 @@
      *
      * @param neededExecMemBytes - executable memory needed by the
      *                           app
+     *
+     * @hide
      */
     public void setNeededExecMemBytes(int neededExecMemBytes) {
         mNeededExecMemBytes = neededExecMemBytes;
@@ -187,6 +201,8 @@
      * set the sensors needed by this app
      *
      * @param neededSensors - all the sensors needed by this app
+     *
+     * @hide
      */
     public void setNeededSensors(int[] neededSensors) {
         mNeededSensors = neededSensors;
@@ -206,6 +222,8 @@
      *
      * @param outputEvents - the events that may be generated by
      *                     this app
+     *
+     * @hide
      */
     public void setOutputEvents(int[] outputEvents) {
         mOutputEvents = outputEvents;
@@ -224,6 +242,8 @@
      * set the context hub identifier
      *
      * @param contexthubId - system wide unique identifier
+     *
+     * @hide
      */
     public void setContexthubId(int contexthubId) {
         mContexthubId = contexthubId;
@@ -242,6 +262,8 @@
      * set the handle for an app instance
      *
      * @param handle - handle to this instance
+     *
+     * @hide
      */
     public void setHandle(int handle) {
         mHandle = handle;
@@ -252,7 +274,7 @@
         mPublisher = in.readString();
         mName = in.readString();
 
-        mAppId = in.readInt();
+        mAppId = in.readLong();
         mAppVersion = in.readInt();
         mNeededReadMemBytes = in.readInt();
         mNeededWriteMemBytes = in.readInt();
@@ -274,7 +296,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mPublisher);
         out.writeString(mName);
-        out.writeInt(mAppId);
+        out.writeLong(mAppId);
         out.writeInt(mAppVersion);
         out.writeInt(mContexthubId);
         out.writeInt(mNeededReadMemBytes);
@@ -286,7 +308,6 @@
 
         out.writeInt(mOutputEvents.length);
         out.writeIntArray(mOutputEvents);
-
     }
 
     public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6b79a8a..9d53a00 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -295,9 +295,7 @@
     boolean mLastShowInputRequested;
     int mCandidatesVisibility;
     CompletionInfo[] mCurCompletions;
-    
-    boolean mShowInputForced;
-    
+
     boolean mFullscreenApplied;
     boolean mIsFullscreen;
     View mExtractView;
@@ -422,7 +420,6 @@
             boolean wasVis = isInputViewShown();
             mShowInputFlags = 0;
             mShowInputRequested = false;
-            mShowInputForced = false;
             doHideWindow();
             clearInsetOfPreviousIme();
             if (resultReceiver != null) {
@@ -439,8 +436,7 @@
         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "showSoftInput()");
             boolean wasVis = isInputViewShown();
-            mShowInputFlags = 0;
-            if (onShowInputRequested(flags, false)) {
+            if (dispatchOnShowInputRequested(flags, false)) {
                 try {
                     showWindow(true);
                 } catch (BadTokenException e) {
@@ -817,8 +813,8 @@
         mInitialized = false;
         mWindowCreated = false;
         mShowInputRequested = false;
-        mShowInputForced = false;
-        
+        mShowInputFlags = 0;
+
         mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
         mRootView = mInflater.inflate(
                 com.android.internal.R.layout.input_method, null);
@@ -888,7 +884,7 @@
      */
     @Override public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        
+
         boolean visible = mWindowVisible;
         int showFlags = mShowInputFlags;
         boolean showingInput = mShowInputRequested;
@@ -903,7 +899,7 @@
         if (visible) {
             if (showingInput) {
                 // If we were last showing the soft keyboard, try to do so again.
-                if (onShowInputRequested(showFlags, true)) {
+                if (dispatchOnShowInputRequested(showFlags, true)) {
                     showWindow(true);
                     if (completions != null) {
                         mCurCompletions = completions;
@@ -1540,20 +1536,41 @@
                 return false;
             }
         }
-        if ((flags&InputMethod.SHOW_FORCED) != 0) {
-            mShowInputForced = true;
-        }
         return true;
     }
-    
+
+    /**
+     * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
+     * states depending on its result.  Since {@link #onShowInputRequested(int, boolean)} is
+     * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
+     * to have this method to ensure that those internal states are always updated no matter how
+     * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
+     * @param flags Provides additional information about the show request,
+     * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+     * @param configChange This is true if we are re-showing due to a
+     * configuration change.
+     * @return Returns true to indicate that the window should be shown.
+     * @see #onShowInputRequested(int, boolean)
+     */
+    private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
+        final boolean result = onShowInputRequested(flags, configChange);
+        if (result) {
+            mShowInputFlags = flags;
+        } else {
+            mShowInputFlags = 0;
+        }
+        return result;
+    }
+
     public void showWindow(boolean showInput) {
         if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
                 + " mShowInputRequested=" + mShowInputRequested
                 + " mWindowAdded=" + mWindowAdded
                 + " mWindowCreated=" + mWindowCreated
                 + " mWindowVisible=" + mWindowVisible
-                + " mInputStarted=" + mInputStarted);
-        
+                + " mInputStarted=" + mInputStarted
+                + " mShowInputFlags=" + mShowInputFlags);
+
         if (mInShowWindow) {
             Log.w(TAG, "Re-entrance in to showWindow");
             return;
@@ -2573,7 +2590,6 @@
         
         p.println("  mShowInputRequested=" + mShowInputRequested
                 + " mLastShowInputRequested=" + mLastShowInputRequested
-                + " mShowInputForced=" + mShowInputForced
                 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
         p.println("  mCandidatesVisibility=" + mCandidatesVisibility
                 + " mFullscreenApplied=" + mFullscreenApplied
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 97bd5d2..8c5f603 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -40,6 +40,9 @@
 
     public int leaseDuration;
 
+    /** Link MTU option. 0 means unset. */
+    public int mtu;
+
     public DhcpResults() {
         super();
     }
@@ -57,19 +60,7 @@
             serverAddress = source.serverAddress;
             vendorInfo = source.vendorInfo;
             leaseDuration = source.leaseDuration;
-        }
-    }
-
-    /**
-     * Updates the DHCP fields that need to be retained from
-     * original DHCP request if the current renewal shows them
-     * being empty.
-     */
-    public void updateFromDhcpRequest(DhcpResults orig) {
-        if (orig == null) return;
-        if (gateway == null) gateway = orig.gateway;
-        if (dnsServers.size() == 0) {
-            dnsServers.addAll(orig.dnsServers);
+            mtu = source.mtu;
         }
     }
 
@@ -89,6 +80,7 @@
         super.clear();
         vendorInfo = null;
         leaseDuration = 0;
+        mtu = 0;
     }
 
     @Override
@@ -98,6 +90,7 @@
         str.append(" DHCP server ").append(serverAddress);
         str.append(" Vendor info ").append(vendorInfo);
         str.append(" lease ").append(leaseDuration).append(" seconds");
+        if (mtu != 0) str.append(" MTU ").append(mtu);
 
         return str.toString();
     }
@@ -113,7 +106,8 @@
         return super.equals((StaticIpConfiguration) obj) &&
                 Objects.equals(serverAddress, target.serverAddress) &&
                 Objects.equals(vendorInfo, target.vendorInfo) &&
-                leaseDuration == target.leaseDuration;
+                leaseDuration == target.leaseDuration &&
+                mtu == target.mtu;
     }
 
     /** Implement the Parcelable interface */
@@ -134,6 +128,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeInt(leaseDuration);
+        dest.writeInt(mtu);
         NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
         dest.writeString(vendorInfo);
     }
@@ -141,6 +136,7 @@
     private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
         StaticIpConfiguration.readFromParcel(dhcpResults, in);
         dhcpResults.leaseDuration = in.readInt();
+        dhcpResults.mtu = in.readInt();
         dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
         dhcpResults.vendorInfo = in.readString();
     }
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 8738424..e464a4a 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -57,6 +57,10 @@
     public static final int RULE_REJECT_METERED = 1;
     /** Reject traffic on all networks. */
     public static final int RULE_REJECT_ALL = 2;
+    /** Allow traffic on metered networks. */
+    public static final int RULE_ALLOW_METERED = 3;
+    /** Temporarily allow traffic on metered networks because app is on foreground. */
+    public static final int RULE_TEMPORARY_ALLOW_METERED = 4;
 
     public static final int FIREWALL_RULE_DEFAULT = 0;
     public static final int FIREWALL_RULE_ALLOW = 1;
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 6fdb0d0..4a06fb1 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -16,8 +16,11 @@
 
 package android.net.nsd;
 
+import android.annotation.NonNull;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.text.TextUtils;
+import android.util.Base64;
 import android.util.Log;
 import android.util.ArrayMap;
 
@@ -95,8 +98,99 @@
         mPort = p;
     }
 
+    /**
+     * Unpack txt information from a base-64 encoded byte array.
+     *
+     * @param rawRecords The raw base64 encoded records string read from netd.
+     *
+     * @hide
+     */
+    public void setTxtRecords(@NonNull String rawRecords) {
+        byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT);
+
+        // There can be multiple TXT records after each other. Each record has to following format:
+        //
+        // byte                  type                  required   meaning
+        // -------------------   -------------------   --------   ----------------------------------
+        // 0                     unsigned 8 bit        yes        size of record excluding this byte
+        // 1 - n                 ASCII but not '='     yes        key
+        // n + 1                 '='                   optional   separator of key and value
+        // n + 2 - record size   uninterpreted bytes   optional   value
+        //
+        // Example legal records:
+        // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff]
+        // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '=']
+        // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y']
+        //
+        // Example corrupted records
+        // [3, =, 1, 2]    <- key is empty
+        // [3, 0, =, 2]    <- key contains non-ASCII character. We handle this by replacing the
+        //                    invalid characters instead of skipping the record.
+        // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we
+        //                    handle this by reducing the length of the record as needed.
+        int pos = 0;
+        while (pos < txtRecordsRawBytes.length) {
+            // recordLen is an unsigned 8 bit value
+            int recordLen = txtRecordsRawBytes[pos] & 0xff;
+            pos += 1;
+
+            try {
+                if (recordLen == 0) {
+                    throw new IllegalArgumentException("Zero sized txt record");
+                } else if (pos + recordLen > txtRecordsRawBytes.length) {
+                    Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen);
+                    recordLen = txtRecordsRawBytes.length - pos;
+                }
+
+                // Decode key-value records
+                String key = null;
+                byte[] value = null;
+                int valueLen = 0;
+                for (int i = pos; i < pos + recordLen; i++) {
+                    if (key == null) {
+                        if (txtRecordsRawBytes[i] == '=') {
+                            key = new String(txtRecordsRawBytes, pos, i - pos,
+                                    StandardCharsets.US_ASCII);
+                        }
+                    } else {
+                        if (value == null) {
+                            value = new byte[recordLen - key.length() - 1];
+                        }
+                        value[valueLen] = txtRecordsRawBytes[i];
+                        valueLen++;
+                    }
+                }
+
+                // If '=' was not found we have a boolean record
+                if (key == null) {
+                    key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII);
+                }
+
+                if (TextUtils.isEmpty(key)) {
+                    // Empty keys are not allowed (RFC6763 6.4)
+                    throw new IllegalArgumentException("Invalid txt record (key is empty)");
+                }
+
+                if (getAttributes().containsKey(key)) {
+                    // When we have a duplicate record, the later ones are ignored (RFC6763 6.4)
+                    throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")");
+                }
+
+                setAttribute(key, value);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage());
+            }
+
+            pos += recordLen;
+        }
+    }
+
     /** @hide */
     public void setAttribute(String key, byte[] value) {
+        if (TextUtils.isEmpty(key)) {
+            throw new IllegalArgumentException("Key cannot be empty");
+        }
+
         // Key must be printable US-ASCII, excluding =.
         for (int i = 0; i < key.length(); ++i) {
             char character = key.charAt(i);
@@ -177,10 +271,10 @@
     }
 
     /** @hide */
-    public byte[] getTxtRecord() {
+    public @NonNull byte[] getTxtRecord() {
         int txtRecordSize = getTxtRecordSize();
         if (txtRecordSize == 0) {
-            return null;
+            return new byte[]{};
         }
 
         byte[] txtRecord = new byte[txtRecordSize];
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 6e50155..b6c919e 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -20,6 +20,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.MathUtils;
+import android.util.Slog;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -229,7 +230,7 @@
         }
 
         if (sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
-            Log.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+            Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
                     + "clobber all data inside!", new Throwable());
         }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index be82d56a..8e2dd6b 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -212,6 +212,7 @@
     private static final String WIFI_CONTROLLER_DATA = "wfcd";
     private static final String GLOBAL_BLUETOOTH_CONTROLLER_DATA = "gble";
     private static final String BLUETOOTH_CONTROLLER_DATA = "ble";
+    private static final String BLUETOOTH_MISC_DATA = "blem";
     private static final String MISC_DATA = "m";
     private static final String GLOBAL_NETWORK_DATA = "gn";
     private static final String GLOBAL_MODEM_CONTROLLER_DATA = "gmcd";
@@ -3071,6 +3072,15 @@
             dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
                     u.getWifiControllerActivity(), which);
 
+            // Dump Bluetooth scan data, per UID.
+            final long bleScanTimeUs = u.getBluetoothScanTimer().getTotalTimeLocked(
+                    rawRealtime, which);
+            final int bleScanCount = u.getBluetoothScanTimer().getCountLocked(which);
+            if (bleScanTimeUs != 0 || bleScanCount != 0) {
+                dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA,
+                        bleScanTimeUs / 1000, bleScanCount);
+            }
+
             dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA,
                     u.getBluetoothControllerActivity(), which);
 
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 05dd48b..1128074 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -208,6 +208,18 @@
     }
 
     /**
+     * Removes any entry with the given key from the mapping of this Bundle.
+     *
+     * @param key a String key
+     */
+    public void remove(String key) {
+        super.remove(key);
+        if ((mFlags & FLAG_HAS_FDS) != 0) {
+            mFlags &= ~FLAG_HAS_FDS_KNOWN;
+        }
+    }
+
+    /**
      * Inserts all mappings from the given Bundle into this Bundle.
      *
      * @param bundle a Bundle
@@ -288,6 +300,8 @@
 
             if (fdFound) {
                 mFlags |= FLAG_HAS_FDS;
+            } else {
+                mFlags &= ~FLAG_HAS_FDS;
             }
             mFlags |= FLAG_HAS_FDS_KNOWN;
         }
@@ -315,6 +329,8 @@
                 mMap.removeAt(i);
             }
         }
+        mFlags |= FLAG_HAS_FDS_KNOWN;
+        mFlags &= ~FLAG_HAS_FDS;
     }
 
     /**
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index f13e5b5..9d362d6 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -48,7 +48,8 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-        TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN
+        TEMPERATURE_CURRENT, TEMPERATURE_THROTTLING, TEMPERATURE_SHUTDOWN,
+                TEMPERATURE_THROTTLING_BELOW_VR_MIN
     })
     public @interface TemperatureSource {}
 
@@ -77,6 +78,12 @@
     /** Get shutdown temperature threshold. */
     public static final int TEMPERATURE_SHUTDOWN = 2;
 
+    /**
+     * Get throttling temperature threshold above which minimum clockrates for VR mode will not be
+     * met.
+     */
+    public static final int TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3;
+
     /** Undefined temperature constant. */
     public static final float UNDEFINED_TEMPERATURE = -Float.MAX_VALUE;
 
@@ -96,7 +103,8 @@
      * {@link #DEVICE_TEMPERATURE_GPU}, {@link #DEVICE_TEMPERATURE_BATTERY} or {@link
      * #DEVICE_TEMPERATURE_SKIN}.
      * @param source source of requested device temperature, one of {@link #TEMPERATURE_CURRENT},
-     * {@link #TEMPERATURE_THROTTLING} or {@link #TEMPERATURE_SHUTDOWN}.
+     * {@link #TEMPERATURE_THROTTLING}, {@link #TEMPERATURE_THROTTLING_BELOW_VR_MIN} or
+     * {@link #TEMPERATURE_SHUTDOWN}.
      * @return an array of requested float device temperatures. Temperature equals to
      *         {@link #UNDEFINED_TEMPERATURE} if undefined.
      *         Empty if platform doesn't provide the queried temperature.
@@ -115,6 +123,7 @@
                     case TEMPERATURE_CURRENT:
                     case TEMPERATURE_THROTTLING:
                     case TEMPERATURE_SHUTDOWN:
+                    case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
                         try {
                             return mService.getDeviceTemperatures(mContext.getOpPackageName(), type,
                                     source);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8bc903b..ce176a3 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -224,8 +224,6 @@
      * This is used by Gaming and VR applications to ensure the device provides
      * will provide consistent performance over a large amount of time.
      * </p>
-     *
-     * {@hide}
      */
     public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
 
@@ -1033,6 +1031,16 @@
     }
 
     /**
+     * Returns True if the device supports Sustained Performance Mode.
+     * Applications Should check if the device supports this mode, before
+     * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+     */
+    public boolean isSustainedPerformanceModeSupported() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_sustainedPerformanceModeSupported);
+    }
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
      * This broadcast is only sent to registered receivers.
      */
diff --git a/core/java/android/os/health/TimerStat.java b/core/java/android/os/health/TimerStat.java
index fc51b60..b9d8874 100644
--- a/core/java/android/os/health/TimerStat.java
+++ b/core/java/android/os/health/TimerStat.java
@@ -27,7 +27,7 @@
  * object to be constructed, even internally, but the getTimers method on
  * {@link android.os.health.HealthStats} does require TimerStat objects.
  */
-public class TimerStat implements Parcelable {
+public final class TimerStat implements Parcelable {
     private int mCount;
     private long mTime;
 
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index c028e15..7b0d2a4 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -315,27 +315,34 @@
      * To gain access to descendants (child, grandchild, etc) documents, use
      * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)}, or
      * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
-     *
-     * <b>If your application only needs to store internal data, consider using
+     * <p>
+     * If your application only needs to store internal data, consider using
      * {@link Context#getExternalFilesDirs(String) Context.getExternalFilesDirs},
-     * {@link Context#getExternalCacheDirs()}, or
-     * {@link Context#getExternalMediaDirs()}, which require no permissions to read or write.
+     * {@link Context#getExternalCacheDirs()}, or {@link Context#getExternalMediaDirs()}, which
+     * require no permissions to read or write.
+     * <p>
+     * Access to the entire volume is only available for non-primary volumes (for the primary
+     * volume, apps can use the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and
+     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions) and should be used
+     * with caution, since users are more likely to deny access when asked for entire volume access
+     * rather than specific directories.
      *
-     * <strong>NOTE: </strong>requesting access to the entire volume is not recommended and it will
-     * result in a stronger message displayed to the user, which may cause the user to reject
-     * the request.
-     *
-     * @param directoryName must be one of
-     * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS},
-     * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS},
-     * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES},
-     * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS},
-     * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}, or
-     * {code null} to request access to the entire volume.
-     *
+     * @param directoryName must be one of {@link Environment#DIRECTORY_MUSIC},
+     *            {@link Environment#DIRECTORY_PODCASTS}, {@link Environment#DIRECTORY_RINGTONES},
+     *            {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS},
+     *            {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES},
+     *            {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or
+     *            {@link Environment#DIRECTORY_DOCUMENTS}, or {code null} to request access to the
+     *            entire volume.
+     * @return intent to request access, or {@code null} if the requested directory is invalid for
+     *         that volume.
      * @see DocumentsContract
      */
-    public Intent createAccessIntent(String directoryName) {
+    public @Nullable Intent createAccessIntent(String directoryName) {
+        if ((isPrimary() && directoryName == null) ||
+                (directoryName != null && !Environment.isStandardDirectory(directoryName))) {
+            return null;
+        }
         final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
         intent.putExtra(EXTRA_STORAGE_VOLUME, this);
         intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 5eb8cc2..d7c267b 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -24,9 +24,11 @@
 import android.print.PrintJobId;
 import android.print.IPrintJobStateChangeListener;
 import android.print.IPrintServicesChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
 import android.print.PrinterId;
 import android.print.PrintJobInfo;
 import android.print.PrintAttributes;
+import android.printservice.recommendation.RecommendationInfo;
 import android.printservice.PrintServiceInfo;
 
 /**
@@ -73,7 +75,6 @@
      * Get the print services.
      *
      * @param selectionFlags flags selecting which services to get
-     * @param selectedService if not null, the id of the print service to get
      * @param userId the id of the user requesting the services
      *
      * @return the list of selected print services.
@@ -89,6 +90,37 @@
      */
     void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
 
+    /**
+     * Listen for changes to the print service recommendations.
+     *
+     * @param listener the listener to add
+     * @param userId the id of the user listening
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void addPrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+            int userId);
+
+    /**
+     * Stop listening for changes to the print service recommendations.
+     *
+     * @param listener the listener to remove
+     * @param userId the id of the user requesting the removal
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void removePrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+            int userId);
+
+    /**
+     * Get the print service recommendations.
+     *
+     * @param userId the id of the user requesting the recommendations
+     *
+     * @return the list of selected print services.
+     */
+    List<RecommendationInfo> getPrintServiceRecommendations(int userId);
+
     void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
     void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
             in List<PrinterId> priorityList, int userId);
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 57c7718..2941283 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -32,6 +32,9 @@
      */
     public static final PageRange ALL_PAGES = new PageRange(0, Integer.MAX_VALUE);
 
+    /** @hide */
+    public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
+
     private final int mStart;
     private final int mEnd;
 
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e9c196d..721c94e 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -20,6 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources.NotFoundException;
@@ -31,6 +32,7 @@
 import android.util.Log;
 
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -49,7 +51,7 @@
     @IntDef(flag = true, value = {
             COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
     })
-    public @interface ColorMode {
+    @interface ColorMode {
     }
     /** Color mode: Monochrome color scheme, for example one color is used. */
     public static final int COLOR_MODE_MONOCHROME = 1 << 0;
@@ -64,7 +66,7 @@
     @IntDef(flag = true, value = {
             DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
     })
-    public @interface DuplexMode {
+    @interface DuplexMode {
     }
     /** Duplex mode: No duplexing. */
     public static final int DUPLEX_MODE_NONE = 1 << 0;
@@ -76,23 +78,29 @@
     private static final int VALID_DUPLEX_MODES =
             DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
 
-    private MediaSize mMediaSize;
-    private Resolution mResolution;
-    private Margins mMinMargins;
+    private @Nullable MediaSize mMediaSize;
+    private @Nullable Resolution mResolution;
+    private @Nullable Margins mMinMargins;
 
-    private int mColorMode;
-    private int mDuplexMode;
+    private @IntRange(from = 0) int mColorMode;
+    private @IntRange(from = 0) int mDuplexMode;
 
     PrintAttributes() {
         /* hide constructor */
     }
 
     private PrintAttributes(@NonNull Parcel parcel) {
-        mMediaSize = (parcel.readInt() ==  1) ? MediaSize.createFromParcel(parcel) : null;
-        mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
-        mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
+        mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
+        mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
+        mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
         mColorMode = parcel.readInt();
+        if (mColorMode != 0) {
+            enforceValidColorMode(mColorMode);
+        }
         mDuplexMode = parcel.readInt();
+        if (mDuplexMode != 0) {
+            enforceValidDuplexMode(mDuplexMode);
+        }
     }
 
     /**
@@ -179,7 +187,7 @@
      * @see #COLOR_MODE_COLOR
      * @see #COLOR_MODE_MONOCHROME
      */
-    public @ColorMode int getColorMode() {
+    public @IntRange(from = 0) int getColorMode() {
         return mColorMode;
     }
 
@@ -214,13 +222,13 @@
     /**
      * Gets the duplex mode.
      *
-     * @return The duplex mode.
+     * @return The duplex mode or zero if not set.
      *
      * @see #DUPLEX_MODE_NONE
      * @see #DUPLEX_MODE_LONG_EDGE
      * @see #DUPLEX_MODE_SHORT_EDGE
      */
-    public @DuplexMode int getDuplexMode() {
+    public @IntRange(from = 0) int getDuplexMode() {
         return mDuplexMode;
     }
 
@@ -448,7 +456,7 @@
         private static final String LOG_TAG = "MediaSize";
 
         private static final Map<String, MediaSize> sIdToMediaSizeMap =
-                new ArrayMap<String, MediaSize>();
+                new ArrayMap<>();
 
         /**
          * Unknown media size in portrait mode.
@@ -781,15 +789,15 @@
                 new MediaSize("JPN_YOU4", "android",
                         R.string.mediasize_japanese_you4, 4134, 9252);
 
-        private final String mId;
+        private final @NonNull String mId;
         /**@hide */
-        public final String mLabel;
+        public final @NonNull String mLabel;
         /**@hide */
-        public final String mPackageName;
+        public final @Nullable String mPackageName;
         /**@hide */
-        public final int mLabelResId;
-        private final int mWidthMils;
-        private final int mHeightMils;
+        public final @StringRes int mLabelResId;
+        private final @IntRange(from = 1) int mWidthMils;
+        private final @IntRange(from = 1) int mHeightMils;
 
         /**
          * Creates a new instance.
@@ -808,29 +816,7 @@
          */
         public MediaSize(String id, String packageName, int labelResId,
                 int widthMils, int heightMils) {
-            if (TextUtils.isEmpty(id)) {
-                throw new IllegalArgumentException("id cannot be empty.");
-            }
-            if (TextUtils.isEmpty(packageName)) {
-                throw new IllegalArgumentException("packageName cannot be empty.");
-            }
-            if (labelResId <= 0) {
-                throw new IllegalArgumentException("labelResId must be greater than zero.");
-            }
-            if (widthMils <= 0) {
-                throw new IllegalArgumentException("widthMils "
-                        + "cannot be less than or equal to zero.");
-            }
-            if (heightMils <= 0) {
-                throw new IllegalArgumentException("heightMils "
-                       + "cannot be less than or euqual to zero.");
-            }
-            mPackageName = packageName;
-            mId = id;
-            mLabelResId = labelResId;
-            mWidthMils = widthMils;
-            mHeightMils = heightMils;
-            mLabel = null;
+            this(id, null, packageName, widthMils, heightMils, labelResId);
 
             // Build this mapping only for predefined media sizes.
             sIdToMediaSizeMap.put(mId, this);
@@ -851,26 +837,7 @@
          */
         public MediaSize(@NonNull String id, @NonNull String label,
                 @IntRange(from = 1) int widthMils, @IntRange(from = 1) int heightMils) {
-            if (TextUtils.isEmpty(id)) {
-                throw new IllegalArgumentException("id cannot be empty.");
-            }
-            if (TextUtils.isEmpty(label)) {
-                throw new IllegalArgumentException("label cannot be empty.");
-            }
-            if (widthMils <= 0) {
-                throw new IllegalArgumentException("widthMils "
-                        + "cannot be less than or equal to zero.");
-            }
-            if (heightMils <= 0) {
-                throw new IllegalArgumentException("heightMils "
-                       + "cannot be less than or euqual to zero.");
-            }
-            mId = id;
-            mLabel = label;
-            mWidthMils = widthMils;
-            mHeightMils = heightMils;
-            mLabelResId = 0;
-            mPackageName = null;
+            this(id, label, null, widthMils, heightMils, 0);
         }
 
         /**
@@ -890,15 +857,37 @@
             return definedMediaSizes;
         }
 
-        /** @hide */
-        public MediaSize(String id, String label, String packageName,
-                int widthMils, int heightMils, int labelResId) {
+        /**
+         * Creates a new instance.
+         *
+         * @param id The unique media size id. It is unique amongst other media sizes
+         *        supported by the printer.
+         * @param label The <strong>localized</strong> human readable label.
+         * @param packageName The name of the creating package.
+         * @param widthMils The width in mils (thousands of an inch).
+         * @param heightMils The height in mils (thousands of an inch).
+         * @param labelResId The resource if of a human readable label.
+         *
+         * @throws IllegalArgumentException If the id is empty or the label is unset
+         * or the widthMils is less than or equal to zero or the heightMils is less
+         * than or equal to zero.
+         *
+         * @hide
+         */
+        public MediaSize(String id, String label, String packageName, int widthMils, int heightMils,
+                int labelResId) {
             mPackageName = packageName;
-            mId = id;
+            mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty.");
             mLabelResId = labelResId;
-            mWidthMils = widthMils;
-            mHeightMils = heightMils;
+            mWidthMils = Preconditions.checkArgumentPositive(widthMils, "widthMils cannot be " +
+                    "less than or equal to zero.");
+            mHeightMils = Preconditions.checkArgumentPositive(heightMils, "heightMils cannot be " +
+                    "less than or equal to zero.");
             mLabel = label;
+
+            // The label has to be either a string ot a StringRes
+            Preconditions.checkArgument(!TextUtils.isEmpty(label) !=
+                    (!TextUtils.isEmpty(packageName) && labelResId != 0), "label cannot be empty.");
         }
 
         /**
@@ -926,10 +915,7 @@
                 try {
                     return packageManager.getResourcesForApplication(
                             mPackageName).getString(mLabelResId);
-                } catch (NotFoundException nfe) {
-                    Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
-                            + " from package " + mPackageName);
-                } catch (NameNotFoundException nnfee) {
+                } catch (NotFoundException | NameNotFoundException e) {
                     Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
                             + " from package " + mPackageName);
                 }
@@ -1084,10 +1070,10 @@
      * the one with 300 DPI resolution.
      */
     public static final class Resolution {
-        private final String mId;
-        private final String mLabel;
-        private final int mHorizontalDpi;
-        private final int mVerticalDpi;
+        private final @NonNull String mId;
+        private final @NonNull String mLabel;
+        private final @IntRange(from = 1) int mHorizontalDpi;
+        private final @IntRange(from = 1) int mVerticalDpi;
 
         /**
          * Creates a new instance.
@@ -1244,8 +1230,7 @@
          * @param rightMils The right margin in mils (thousands of an inch).
          * @param bottomMils The bottom margin in mils (thousands of an inch).
          */
-        public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
-                @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
+        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
             mTopMils = topMils;
             mLeftMils = leftMils;
             mRightMils = rightMils;
@@ -1257,7 +1242,7 @@
          *
          * @return The left margin.
          */
-        public @IntRange(from = 0) int getLeftMils() {
+        public int getLeftMils() {
             return mLeftMils;
         }
 
@@ -1266,7 +1251,7 @@
          *
          * @return The top margin.
          */
-        public @IntRange(from = 0) int getTopMils() {
+        public int getTopMils() {
             return mTopMils;
         }
 
@@ -1275,7 +1260,7 @@
          *
          * @return The right margin.
          */
-        public @IntRange(from = 0) int getRightMils() {
+        public int getRightMils() {
             return mRightMils;
         }
 
@@ -1284,7 +1269,7 @@
          *
          * @return The bottom margin.
          */
-        public @IntRange(from = 0) int getBottomMils() {
+        public int getBottomMils() {
             return mBottomMils;
         }
 
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index db3b6f4..bec6f29 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -22,6 +22,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -114,8 +115,8 @@
      */
     public static final int CONTENT_TYPE_PHOTO = 1;
 
-    private String mName;
-    private int mPageCount;
+    private @NonNull String mName;
+    private @IntRange(from = -1) int mPageCount;
     private int mContentType;
     private long mDataSize;
 
@@ -144,10 +145,11 @@
      * @param parcel Data from which to initialize.
      */
     private PrintDocumentInfo(Parcel parcel) {
-        mName = parcel.readString();
+        mName = Preconditions.checkStringNotEmpty(parcel.readString());
         mPageCount = parcel.readInt();
+        Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
         mContentType = parcel.readInt();
-        mDataSize = parcel.readLong();
+        mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
     }
 
     /**
@@ -180,7 +182,7 @@
      * @see #CONTENT_TYPE_DOCUMENT
      * @see #CONTENT_TYPE_PHOTO
      */
-    public @ContentType int getContentType() {
+    public int getContentType() {
         return mContentType;
     }
 
@@ -262,13 +264,13 @@
         builder.append("PrintDocumentInfo{");
         builder.append("name=").append(mName);
         builder.append(", pageCount=").append(mPageCount);
-        builder.append(", contentType=").append(contentTyepToString(mContentType));
+        builder.append(", contentType=").append(contentTypeToString(mContentType));
         builder.append(", dataSize=").append(mDataSize);
         builder.append("}");
         return builder.toString();
     }
 
-    private String contentTyepToString(int contentType) {
+    private String contentTypeToString(int contentType) {
         switch (contentType) {
             case CONTENT_TYPE_DOCUMENT: {
                 return "CONTENT_TYPE_DOCUMENT";
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 25fc968..71f0bd6 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -36,12 +36,15 @@
 import android.print.PrintDocumentAdapter.LayoutResultCallback;
 import android.print.PrintDocumentAdapter.WriteResultCallback;
 import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.printservice.recommendation.RecommendationInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.internal.os.SomeArgs;
 
+import com.android.internal.util.Preconditions;
 import libcore.io.IoUtils;
 
 import java.lang.ref.WeakReference;
@@ -113,6 +116,7 @@
 
     private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
     private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
+    private static final int MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED = 3;
 
     /**
      * Package name of print spooler.
@@ -202,6 +206,9 @@
             mPrintJobStateChangeListeners;
     private Map<PrintServicesChangeListener, PrintServicesChangeListenerWrapper>
             mPrintServicesChangeListeners;
+    private Map<PrintServiceRecommendationsChangeListener,
+            PrintServiceRecommendationsChangeListenerWrapper>
+            mPrintServiceRecommendationsChangeListeners;
 
     /** @hide */
     public interface PrintJobStateChangeListener {
@@ -223,6 +230,15 @@
         public void onPrintServicesChanged();
     }
 
+    /** @hide */
+    public interface PrintServiceRecommendationsChangeListener {
+
+        /**
+         * Callback notifying that the print service recommendations changed.
+         */
+        void onPrintServiceRecommendationsChanged();
+    }
+
     /**
      * Creates a new instance.
      *
@@ -260,7 +276,14 @@
                             listener.onPrintServicesChanged();
                         }
                     } break;
-
+                    case MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED: {
+                        PrintServiceRecommendationsChangeListenerWrapper wrapper =
+                                (PrintServiceRecommendationsChangeListenerWrapper) message.obj;
+                        PrintServiceRecommendationsChangeListener listener = wrapper.getListener();
+                        if (listener != null) {
+                            listener.onPrintServiceRecommendationsChanged();
+                        }
+                    } break;
                 }
             }
         };
@@ -539,13 +562,14 @@
      * @see android.print.PrintManager#getPrintServices
      */
     void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
             return;
         }
         if (mPrintServicesChangeListeners == null) {
-            mPrintServicesChangeListeners = new ArrayMap<PrintServicesChangeListener,
-                    PrintServicesChangeListenerWrapper>();
+            mPrintServicesChangeListeners = new ArrayMap<>();
         }
         PrintServicesChangeListenerWrapper wrappedListener =
                 new PrintServicesChangeListenerWrapper(listener, mHandler);
@@ -565,6 +589,8 @@
      * @see android.print.PrintManager#getPrintServices
      */
     void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
             return;
@@ -588,7 +614,6 @@
         }
     }
 
-
     /**
      * Gets the list of print services, but does not register for updates. The user has to register
      * for updates by itself, or use {@link PrintServicesLoader}.
@@ -596,7 +621,7 @@
      * @param selectionFlags flags selecting which services to get. Either
      *                       {@link #ENABLED_SERVICES},{@link #DISABLED_SERVICES}, or both.
      *
-     * @return The enabled service list or an empty list.
+     * @return The print service list or an empty list.
      *
      * @see #addPrintServicesChangeListener(PrintServicesChangeListener)
      * @see #removePrintServicesChangeListener(PrintServicesChangeListener)
@@ -604,6 +629,8 @@
      * @hide
      */
     public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
+        Preconditions.checkFlagsArgument(selectionFlags, ALL_SERVICES);
+
         try {
             List<PrintServiceInfo> services = mService.getPrintServices(selectionFlags, mUserId);
             if (services != null) {
@@ -616,6 +643,92 @@
     }
 
     /**
+     * Listen for changes to the print service recommendations.
+     *
+     * @param listener the listener to add
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void addPrintServiceRecommendationsChangeListener(
+            @NonNull PrintServiceRecommendationsChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
+        if (mPrintServiceRecommendationsChangeListeners == null) {
+            mPrintServiceRecommendationsChangeListeners = new ArrayMap<>();
+        }
+        PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+                new PrintServiceRecommendationsChangeListenerWrapper(listener, mHandler);
+        try {
+            mService.addPrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+            mPrintServiceRecommendationsChangeListeners.put(listener, wrappedListener);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop listening for changes to the print service recommendations.
+     *
+     * @param listener the listener to remove
+     *
+     * @see android.print.PrintManager#getPrintServiceRecommendations
+     */
+    void removePrintServiceRecommendationsChangeListener(
+            @NonNull PrintServiceRecommendationsChangeListener listener) {
+        Preconditions.checkNotNull(listener);
+
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
+        if (mPrintServiceRecommendationsChangeListeners == null) {
+            return;
+        }
+        PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+                mPrintServiceRecommendationsChangeListeners.remove(listener);
+        if (wrappedListener == null) {
+            return;
+        }
+        if (mPrintServiceRecommendationsChangeListeners.isEmpty()) {
+            mPrintServiceRecommendationsChangeListeners = null;
+        }
+        wrappedListener.destroy();
+        try {
+            mService.removePrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the list of print service recommendations, but does not register for updates. The user
+     * has to register for updates by itself, or use {@link PrintServiceRecommendationsLoader}.
+     *
+     * @return The print service recommendations list or an empty list.
+     *
+     * @see #addPrintServiceRecommendationsChangeListener
+     * @see #removePrintServiceRecommendationsChangeListener
+     *
+     * @hide
+     */
+    public @NonNull List<RecommendationInfo> getPrintServiceRecommendations() {
+        try {
+            List<RecommendationInfo> recommendations =
+                    mService.getPrintServiceRecommendations(mUserId);
+            if (recommendations != null) {
+                return recommendations;
+            }
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+        return Collections.emptyList();
+    }
+
+    /**
      * @hide
      */
     public PrinterDiscoverySession createPrinterDiscoverySession() {
@@ -1242,4 +1355,37 @@
             return mWeakListener.get();
         }
     }
+
+    /**
+     * @hide
+     */
+    public static final class PrintServiceRecommendationsChangeListenerWrapper extends
+            IRecommendationsChangeListener.Stub {
+        private final WeakReference<PrintServiceRecommendationsChangeListener> mWeakListener;
+        private final WeakReference<Handler> mWeakHandler;
+
+        public PrintServiceRecommendationsChangeListenerWrapper(
+                PrintServiceRecommendationsChangeListener listener, Handler handler) {
+            mWeakListener = new WeakReference<>(listener);
+            mWeakHandler = new WeakReference<>(handler);
+        }
+
+        @Override
+        public void onRecommendationsChanged() {
+            Handler handler = mWeakHandler.get();
+            PrintServiceRecommendationsChangeListener listener = mWeakListener.get();
+            if (handler != null && listener != null) {
+                handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED,
+                        this).sendToTarget();
+            }
+        }
+
+        public void destroy() {
+            mWeakListener.clear();
+        }
+
+        public PrintServiceRecommendationsChangeListener getListener() {
+            return mWeakListener.get();
+        }
+    }
 }
diff --git a/core/java/android/print/PrintServiceRecommendationsLoader.java b/core/java/android/print/PrintServiceRecommendationsLoader.java
new file mode 100644
index 0000000..bb5d065
--- /dev/null
+++ b/core/java/android/print/PrintServiceRecommendationsLoader.java
@@ -0,0 +1,121 @@
+/*
+ * 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.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Handler;
+import android.os.Message;
+import android.printservice.recommendation.RecommendationInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print service recommendations.
+ *
+ * @hide
+ */
+public class PrintServiceRecommendationsLoader extends Loader<List<RecommendationInfo>> {
+    /** The print manager to be used by this object */
+    private final @NonNull PrintManager mPrintManager;
+
+    /** Handler to sequentialize the delivery of the results to the main thread */
+    private final Handler mHandler;
+
+    /** Listens for updates to the data from the platform */
+    private PrintManager.PrintServiceRecommendationsChangeListener mListener;
+
+    /**
+     * Create a new PrintServicesLoader.
+     *
+     * @param printManager The print manager supplying the data
+     * @param context      Context of the using object
+     */
+    public PrintServiceRecommendationsLoader(@NonNull PrintManager printManager,
+            @NonNull Context context) {
+        super(Preconditions.checkNotNull(context));
+        mHandler = new MyHandler();
+        mPrintManager = Preconditions.checkNotNull(printManager);
+    }
+
+    @Override
+    protected void onForceLoad() {
+        queueNewResult();
+    }
+
+    /**
+     * Read the print service recommendations and queue it to be delivered on the main thread.
+     */
+    private void queueNewResult() {
+        Message m = mHandler.obtainMessage(0);
+        m.obj = mPrintManager.getPrintServiceRecommendations();
+        mHandler.sendMessage(m);
+    }
+
+    @Override
+    protected void onStartLoading() {
+        mListener = new PrintManager.PrintServiceRecommendationsChangeListener() {
+            @Override
+            public void onPrintServiceRecommendationsChanged() {
+                queueNewResult();
+            }
+        };
+
+        mPrintManager.addPrintServiceRecommendationsChangeListener(mListener);
+
+        // Immediately deliver a result
+        deliverResult(mPrintManager.getPrintServiceRecommendations());
+    }
+
+    @Override
+    protected void onStopLoading() {
+        if (mListener != null) {
+            mPrintManager.removePrintServiceRecommendationsChangeListener(mListener);
+            mListener = null;
+        }
+
+        if (mHandler != null) {
+            mHandler.removeMessages(0);
+        }
+    }
+
+    @Override
+    protected void onReset() {
+        onStopLoading();
+    }
+
+    /**
+     * Handler to sequentialize all the updates to the main thread.
+     */
+    private class MyHandler extends Handler {
+        /**
+         * Create a new handler on the main thread.
+         */
+        public MyHandler() {
+            super(getContext().getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (isStarted()) {
+                deliverResult((List<RecommendationInfo>) msg.obj);
+            }
+        }
+    }
+}
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
index ed41114..60d7d66 100644
--- a/core/java/android/print/PrintServicesLoader.java
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.printservice.PrintServiceInfo;
+import com.android.internal.util.Preconditions;
 
 import java.util.List;
 
@@ -46,13 +47,16 @@
     /**
      * Create a new PrintServicesLoader.
      *
+     * @param printManager   The print manager supplying the data
+     * @param context        Context of the using object
      * @param selectionFlags What type of services to load.
      */
     public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
             int selectionFlags) {
-        super(context);
-        mPrintManager = printManager;
-        mSelectionFlags = selectionFlags;
+        super(Preconditions.checkNotNull(context));
+        mPrintManager = Preconditions.checkNotNull(printManager);
+        mSelectionFlags = Preconditions.checkFlagsArgument(selectionFlags,
+                PrintManager.ALL_SERVICES);
     }
 
     @Override
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index d13879b..01c23f6 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,11 +24,13 @@
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.IntConsumer;
 
 /**
  * This class represents the capabilities of a printer. Instances
@@ -55,9 +57,9 @@
 
     private static final Margins DEFAULT_MARGINS = new Margins(0,  0,  0,  0);
 
-    private Margins mMinMargins = DEFAULT_MARGINS;
-    private List<MediaSize> mMediaSizes;
-    private List<Resolution> mResolutions;
+    private @NonNull Margins mMinMargins = DEFAULT_MARGINS;
+    private @NonNull List<MediaSize> mMediaSizes;
+    private @NonNull List<Resolution> mResolutions;
 
     private int mColorModes;
     private int mDuplexModes;
@@ -205,15 +207,37 @@
         return builder.build();
     }
 
+    /**
+     * Call enforceSingle for each bit in the mask.
+     *
+     * @param mask The mask
+     * @param enforceSingle The function to call
+     */
+    private static void enforceValidMask(int mask, IntConsumer enforceSingle) {
+        int current = mask;
+        while (current > 0) {
+            final int currentMode = (1 << Integer.numberOfTrailingZeros(current));
+            current &= ~currentMode;
+            enforceSingle.accept(currentMode);
+        }
+    }
+
     private PrinterCapabilitiesInfo(Parcel parcel) {
-        mMinMargins = readMargins(parcel);
+        mMinMargins = Preconditions.checkNotNull(readMargins(parcel));
         readMediaSizes(parcel);
         readResolutions(parcel);
 
         mColorModes = parcel.readInt();
+        enforceValidMask(mColorModes,
+                (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
+
         mDuplexModes = parcel.readInt();
+        enforceValidMask(mDuplexModes,
+                (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
 
         readDefaults(parcel);
+        Preconditions.checkArgument(mMediaSizes.size() > mDefaults[PROPERTY_MEDIA_SIZE]);
+        Preconditions.checkArgument(mResolutions.size() > mDefaults[PROPERTY_RESOLUTION]);
     }
 
     @Override
@@ -537,12 +561,8 @@
          */
         public @NonNull Builder setColorModes(@ColorMode int colorModes,
                 @ColorMode int defaultColorMode) {
-            int currentModes = colorModes;
-            while (currentModes > 0) {
-                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
-                currentModes &= ~currentMode;
-                PrintAttributes.enforceValidColorMode(currentMode);
-            }
+            enforceValidMask(colorModes,
+                    (currentMode) -> PrintAttributes.enforceValidColorMode(currentMode));
             PrintAttributes.enforceValidColorMode(defaultColorMode);
             mPrototype.mColorModes = colorModes;
             mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
@@ -568,12 +588,8 @@
          */
         public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
                 @DuplexMode int defaultDuplexMode) {
-            int currentModes = duplexModes;
-            while (currentModes > 0) {
-                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
-                currentModes &= ~currentMode;
-                PrintAttributes.enforceValidDuplexMode(currentMode);
-            }
+            enforceValidMask(duplexModes,
+                    (currentMode) -> PrintAttributes.enforceValidDuplexMode(currentMode));
             PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
             mPrototype.mDuplexModes = duplexModes;
             mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
diff --git a/core/java/android/printservice/recommendation/IRecommendationService.aidl b/core/java/android/printservice/recommendation/IRecommendationService.aidl
new file mode 100644
index 0000000..ce9ea6f
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationService.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
+
+/**
+ * Interface for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationServiceCallbacks
+ *
+ * @hide
+ */
+oneway interface IRecommendationService {
+    void registerCallbacks(in IRecommendationServiceCallbacks callbacks);
+}
diff --git a/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
new file mode 100644
index 0000000..9528654
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.printservice.recommendation.RecommendationInfo;
+
+/**
+ * Callbacks for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationService
+ *
+ * @hide
+ */
+oneway interface IRecommendationServiceCallbacks {
+    /**
+     * Update the print service recommendations.
+     *
+     * @param recommendations the new print service recommendations
+     */
+    void onRecommendationsUpdated(in List<RecommendationInfo> recommendations);
+}
diff --git a/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
new file mode 100644
index 0000000..8ca5c69
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.printservice.recommendation;
+
+/**
+ * Interface for observing changes of the print service recommendations.
+ *
+ * @hide
+ */
+oneway interface IRecommendationsChangeListener {
+    void onRecommendationsChanged();
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.aidl b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
new file mode 100644
index 0000000..f21d0bf
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
@@ -0,0 +1,22 @@
+/**
+ * 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.printservice.recommendation;
+
+/**
+ * @hide
+ */
+parcelable RecommendationInfo;
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.java b/core/java/android/printservice/recommendation/RecommendationInfo.java
new file mode 100644
index 0000000..65d534e
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.java
@@ -0,0 +1,133 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.printservice.PrintService;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A recommendation to install a {@link PrintService print service}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RecommendationInfo implements Parcelable {
+    /** Package name of the print service. */
+    private @NonNull final CharSequence mPackageName;
+
+    /** Display name of the print service. */
+    private @NonNull final CharSequence mName;
+
+    /** Number of printers the print service would discover if installed. */
+    private @IntRange(from = 0) final int mNumDiscoveredPrinters;
+
+    /** If the service detects printer from multiple vendors. */
+    private final boolean mRecommendsMultiVendorService;
+
+    /**
+     * Create a new recommendation.
+     *
+     * @param packageName                  Package name of the print service
+     * @param name                         Display name of the print service
+     * @param numDiscoveredPrinters        Number of printers the print service would discover if
+     *                                     installed
+     * @param recommendsMultiVendorService If the service detects printer from multiple vendor
+     */
+    public RecommendationInfo(@NonNull CharSequence packageName, @NonNull CharSequence name,
+            @IntRange(from = 0) int numDiscoveredPrinters, boolean recommendsMultiVendorService) {
+        mPackageName = Preconditions.checkStringNotEmpty(packageName);
+        mName = Preconditions.checkStringNotEmpty(name);
+        mNumDiscoveredPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters);
+        mRecommendsMultiVendorService = recommendsMultiVendorService;
+    }
+
+    /**
+     * Create a new recommendation from a parcel.
+     *
+     * @param parcel The parcel containing the data
+     *
+     * @see #CREATOR
+     */
+    private RecommendationInfo(@NonNull Parcel parcel) {
+        this(parcel.readCharSequence(), parcel.readCharSequence(), parcel.readInt(),
+                parcel.readByte() != 0);
+    }
+
+    /**
+     * @return The package name the recommendations recommends.
+     */
+    public CharSequence getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return Whether the recommended print service detects printers of more than one vendor.
+     */
+    public boolean recommendsMultiVendorService() {
+        return mRecommendsMultiVendorService;
+    }
+
+    /**
+     * @return The number of printer the print service would detect.
+     */
+    public int getNumDiscoveredPrinters() {
+        return mNumDiscoveredPrinters;
+    }
+
+    /**
+     * @return The name of the recommended print service.
+     */
+    public CharSequence getName() {
+        return mName;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeCharSequence(mPackageName);
+        dest.writeCharSequence(mName);
+        dest.writeInt(mNumDiscoveredPrinters);
+        dest.writeByte((byte) (mRecommendsMultiVendorService ? 1 : 0));
+    }
+
+    /**
+     * Utility class used to create new print service recommendation objects from parcels.
+     *
+     * @see #RecommendationInfo(Parcel)
+     */
+    public static final Creator<RecommendationInfo> CREATOR =
+            new Creator<RecommendationInfo>() {
+                @Override
+                public RecommendationInfo createFromParcel(Parcel in) {
+                    return new RecommendationInfo(in);
+                }
+
+                @Override
+                public RecommendationInfo[] newArray(int size) {
+                    return new RecommendationInfo[size];
+                }
+    };
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationService.java b/core/java/android/printservice/recommendation/RecommendationService.java
new file mode 100644
index 0000000..b7ea512
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationService.java
@@ -0,0 +1,138 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.List;
+
+/**
+ * Base class for the print service recommendation services.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class RecommendationService extends Service {
+    private static final String LOG_TAG = "PrintServiceRecS";
+
+    /** Used to push onConnect and onDisconnect on the main thread */
+    private Handler mHandler;
+
+    /**
+     * The {@link Intent} action that must be declared as handled by a service in its manifest for
+     * the system to recognize it as a print service recommendation service.
+     *
+     * @hide
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.printservice.recommendation.RecommendationService";
+
+    /** Registered callbacks, only modified on main thread */
+    private IRecommendationServiceCallbacks mCallbacks;
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+
+        mHandler = new MyHandler();
+    }
+
+    /**
+     * Update the print service recommendations.
+     *
+     * @param recommendations The new set of recommendations
+     */
+    public final void updateRecommendations(@Nullable List<RecommendationInfo> recommendations) {
+        mHandler.obtainMessage(MyHandler.MSG_UPDATE, recommendations).sendToTarget();
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return new IRecommendationService.Stub() {
+            @Override
+            public void registerCallbacks(IRecommendationServiceCallbacks callbacks) {
+                // The callbacks come in order of the caller on oneway calls. Hence while the caller
+                // cannot know at what time the connection is made, he can know the ordering of
+                // connection and disconnection.
+                //
+                // Similar he cannot know when the disconnection is processed, hence he has to
+                // handle callbacks after calling disconnect.
+                if (callbacks != null) {
+                    mHandler.obtainMessage(MyHandler.MSG_CONNECT, callbacks).sendToTarget();
+                } else {
+                    mHandler.obtainMessage(MyHandler.MSG_DISCONNECT).sendToTarget();
+                }
+            }
+        };
+    }
+
+    /**
+     * Called when the client connects to the recommendation service.
+     */
+    public abstract void onConnected();
+
+    /**
+     * Called when the client disconnects from the recommendation service.
+     */
+    public abstract void onDisconnected();
+
+    private class MyHandler extends Handler {
+        static final int MSG_CONNECT = 1;
+        static final int MSG_DISCONNECT = 2;
+        static final int MSG_UPDATE = 3;
+
+        MyHandler() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_CONNECT:
+                    mCallbacks = (IRecommendationServiceCallbacks) msg.obj;
+                    onConnected();
+                    break;
+                case MSG_DISCONNECT:
+                    onDisconnected();
+                    mCallbacks = null;
+                    break;
+                case MSG_UPDATE:
+                    // Note that there might be a connection change in progress. In this case the
+                    // message is handled as before the change. This is acceptable as the caller of
+                    // the connection change has not guarantee when the connection change binder
+                    // transaction is actually processed.
+                    try {
+                        mCallbacks.onRecommendationsUpdated((List<RecommendationInfo>) msg.obj);
+                    } catch (RemoteException | NullPointerException e) {
+                        Log.e(LOG_TAG, "Could not update recommended services", e);
+                    }
+                    break;
+            }
+        }
+    }
+}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4412459..aba3972 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -112,9 +112,8 @@
      * thumbnail should be rotated.
      *
      * @see MediaStore.Images.ImageColumns#ORIENTATION
-     * @hide
      */
-    public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION";
+    public static final String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
 
     /**
      * Overrides the default prompt text in DocumentsUI when set in an intent.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a78f468..f4d63ac 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1569,9 +1569,8 @@
      * @return true if the calling app can draw on top of other apps, false otherwise.
      */
     public static boolean canDrawOverlays(Context context) {
-        int uid = Binder.getCallingUid();
-        return Settings.isCallingPackageAllowedToDrawOverlays(context, uid, Settings
-                .getPackageNameForUid(context, uid), false);
+        return Settings.isCallingPackageAllowedToDrawOverlays(context, Process.myUid(),
+                context.getOpPackageName(), false);
     }
 
     /**
@@ -3885,9 +3884,8 @@
          * @return true if the calling app can write to system settings, false otherwise
          */
         public static boolean canWrite(Context context) {
-            int uid = Binder.getCallingUid();
-            return isCallingPackageAllowedToWriteSettings(context, uid, getPackageNameForUid(
-                    context, uid), false);
+            return isCallingPackageAllowedToWriteSettings(context, Process.myUid(),
+                    context.getOpPackageName(), false);
         }
     }
 
@@ -3991,6 +3989,7 @@
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
@@ -7258,6 +7257,14 @@
                "wifi_suspend_optimizations_enabled";
 
        /**
+        * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
+        * will enable it. In the future, additional values may be supported.
+        * @hide
+        */
+       public static final String WIFI_VERBOSE_LOGGING_ENABLED =
+               "wifi_verbose_logging_enabled";
+
+       /**
         * The maximum number of times we will retry a connection to an access
         * point for which we have failed in acquiring an IP address from DHCP.
         * A value of N means that we will make N+1 connection attempts in all.
@@ -7679,6 +7686,9 @@
                 BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
         /** {@hide} */
         public static final String
+                BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_";
+        /** {@hide} */
+        public static final String
                 BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
 
         /**
@@ -7834,6 +7844,14 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth pbap client priority.
+         * @hide
+         */
+        public static final String getBluetoothPbapClientPriorityKey(String address) {
+            return BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
          * Get the key that retrieves a bluetooth map priority.
          * @hide
          */
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7af0b05..0557d13 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -35,7 +35,6 @@
 import android.view.ActionMode;
 import android.view.Display;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index a1bc2d1..328fe99 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -300,6 +300,8 @@
             Metrics fm = metrics;
             if (fm == null) {
                 fm = new Metrics();
+            } else {
+                fm.reset();
             }
 
             TextLine line = TextLine.obtain();
@@ -414,8 +416,6 @@
         mEllipsizedCount = end - start;
     }
 
-    private static final char FIRST_RIGHT_TO_LEFT = '\u0590';
-
     private String mDirect;
     private Paint mPaint;
 
@@ -430,5 +430,14 @@
         @Override public String toString() {
             return super.toString() + " width=" + width;
         }
+
+        private void reset() {
+            top = 0;
+            bottom = 0;
+            ascent = 0;
+            descent = 0;
+            width = 0;
+            leading = 0;
+        }
     }
 }
diff --git a/core/java/android/util/Pair.java b/core/java/android/util/Pair.java
index 6027d08..f96da72 100644
--- a/core/java/android/util/Pair.java
+++ b/core/java/android/util/Pair.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import libcore.util.Objects;
+import java.util.Objects;
 
 /**
  * Container to ease passing around a tuple of two objects. This object provides a sensible
@@ -52,7 +52,7 @@
             return false;
         }
         Pair<?, ?> p = (Pair<?, ?>) o;
-        return Objects.equal(p.first, first) && Objects.equal(p.second, second);
+        return Objects.equals(p.first, first) && Objects.equals(p.second, second);
     }
 
     /**
@@ -65,6 +65,11 @@
         return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
     }
 
+    @Override
+    public String toString() {
+        return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
+    }
+
     /**
      * Convenience method for creating an appropriately typed pair.
      * @param a the first object in the Pair
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index d9227ce..78d3b7b 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -606,7 +606,6 @@
     private static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
     private static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
     private static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
-    private static final int SIGNATURE_DSA_WITH_SHA512 = 0x0302;
 
     private static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
     private static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
@@ -620,7 +619,6 @@
             case SIGNATURE_ECDSA_WITH_SHA256:
             case SIGNATURE_ECDSA_WITH_SHA512:
             case SIGNATURE_DSA_WITH_SHA256:
-            case SIGNATURE_DSA_WITH_SHA512:
                 return true;
             default:
                 return false;
@@ -670,7 +668,6 @@
             case SIGNATURE_RSA_PSS_WITH_SHA512:
             case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
             case SIGNATURE_ECDSA_WITH_SHA512:
-            case SIGNATURE_DSA_WITH_SHA512:
                 return CONTENT_DIGEST_CHUNKED_SHA512;
             default:
                 throw new IllegalArgumentException(
@@ -714,7 +711,6 @@
             case SIGNATURE_ECDSA_WITH_SHA512:
                 return "EC";
             case SIGNATURE_DSA_WITH_SHA256:
-            case SIGNATURE_DSA_WITH_SHA512:
                 return "DSA";
             default:
                 throw new IllegalArgumentException(
@@ -746,8 +742,6 @@
                 return Pair.create("SHA512withECDSA", null);
             case SIGNATURE_DSA_WITH_SHA256:
                 return Pair.create("SHA256withDSA", null);
-            case SIGNATURE_DSA_WITH_SHA512:
-                return Pair.create("SHA512withDSA", null);
             default:
                 throw new IllegalArgumentException(
                         "Unknown signature algorithm: 0x"
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7af4a1f..4ba97d5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -180,7 +180,12 @@
     // caller must call setNewConfiguration() sometime later.
     Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
             IBinder freezeThisOneIfNeeded);
-    void setNewConfiguration(in Configuration config);
+    // Notify window manager of the new configuration. Returns an array of stack ids that's
+    // affected by the update, ActivityManager should resize these stacks.
+    int[] setNewConfiguration(in Configuration config);
+
+    // Retrieves the new bounds after the configuration update evaluated by window manager.
+    Rect getBoundsForNewConfiguration(int stackId);
 
     void startFreezingScreen(int exitAnim, int enterAnim);
     void stopFreezingScreen();
@@ -400,4 +405,14 @@
      * @hide
      */
     void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
+
+    /**
+     * Create the input consumer for wallpaper events.
+     */
+    void createWallpaperInputConsumer(out InputChannel inputChannel);
+
+    /**
+     * Remove the input consumer for wallpaper events.
+     */
+    void removeWallpaperInputConsumer();
 }
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index c2bd347..eee925d 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -51,7 +51,7 @@
         mLabel = label;
         mIcon = icon;
         mBaseCharacter = MIN_VALUE;
-        checkArgument(keycode > KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
+        checkArgument(keycode >= KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
         mKeycode = keycode;
         mModifiers = modifiers;
     }
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a19254f..ab4cbcf 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -307,18 +307,22 @@
      *
      * Deep copies the data into native to simplify reference ownership.
      */
-    public boolean setOutline(Outline outline) {
+    public boolean setOutline(@Nullable Outline outline) {
         if (outline == null) {
             return nSetOutlineNone(mNativeRenderNode);
-        } else if (outline.isEmpty()) {
-            return nSetOutlineEmpty(mNativeRenderNode);
-        } else if (outline.mRect != null) {
-            return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
-                    outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
-        } else if (outline.mPath != null) {
-            return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
-                    outline.mAlpha);
         }
+
+        switch(outline.mMode) {
+            case Outline.MODE_EMPTY:
+                return nSetOutlineEmpty(mNativeRenderNode);
+            case Outline.MODE_ROUND_RECT:
+                return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
+                        outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha);
+            case Outline.MODE_CONVEX_PATH:
+                return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
+                        outline.mAlpha);
+        }
+
         throw new IllegalArgumentException("Unrecognized outline?");
     }
 
@@ -763,6 +767,16 @@
         return nGetDebugSize(mNativeRenderNode);
     }
 
+    /**
+     * Called by native when the passed displaylist is removed from the draw tree
+     */
+    void onRenderNodeDetached() {
+        discardDisplayList();
+        if (mOwningView != null) {
+            mOwningView.onRenderNodeDetached(this);
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Animations
     ///////////////////////////////////////////////////////////////////////////
@@ -795,7 +809,9 @@
     // Native methods
     ///////////////////////////////////////////////////////////////////////////
 
-    private static native long nCreate(String name);
+    // Intentionally not static because it acquires a reference to 'this'
+    private native long nCreate(String name);
+
     private static native void nDestroyRenderNode(long renderNode);
     private static native void nSetDisplayList(long renderNode, long newData);
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c972476..df774b4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -794,7 +794,8 @@
         }
 
         final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
-        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length,
+                mRootNode.mNativeRenderNode);
         if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
             setEnabled(false);
             attachInfo.mViewRootImpl.mSurface.release();
@@ -993,7 +994,8 @@
     private static native void nSetLightCenter(long nativeProxy,
             float lightX, float lightY, float lightZ);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
-    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
+    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size,
+            long rootRenderNode);
     private static native void nDestroy(long nativeProxy, long rootRenderNode);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6811aed..117faf0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3890,6 +3890,7 @@
      * cleanup.
      */
     final RenderNode mRenderNode;
+    private Runnable mRenderNodeDetachedCallback;
 
     /**
      * Set to true when the view is sending hover accessibility events because it
@@ -16009,6 +16010,27 @@
     }
 
     /**
+     * Called when the passed RenderNode is removed from the draw tree
+     * @hide
+     */
+    public void onRenderNodeDetached(RenderNode renderNode) {
+        if (renderNode == mRenderNode && mRenderNodeDetachedCallback != null) {
+            mRenderNodeDetachedCallback.run();
+        }
+    }
+
+    /**
+     * Set callback for functor detach. Exposed to WebView through WebViewDelegate.
+     * Should not be used otherwise.
+     * @hide
+     */
+    public final Runnable setRenderNodeDetachedCallback(@Nullable Runnable callback) {
+        Runnable oldCallback = mRenderNodeDetachedCallback;
+        mRenderNodeDetachedCallback = callback;
+        return oldCallback;
+    }
+
+    /**
      * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
      *
      * @return A non-scaled bitmap representing this view or null if cache is disabled.
@@ -16299,8 +16321,10 @@
     /**
      * Create a snapshot of the view into a bitmap.  We should probably make
      * some form of this public, but should think about the API.
+     *
+     * @hide
      */
-    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
+    public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
         int width = mRight - mLeft;
         int height = mBottom - mTop;
 
@@ -18070,13 +18094,7 @@
          * to clear the previous drawable. setVisible first while we still have the callback set.
          */
         if (mBackground != null) {
-            // It's possible for this method to be invoked from the View constructor before
-            // subclass constructors have run. Drawables can and should trigger invalidations
-            // and other activity with their callback on visibility changes, which shouldn't
-            // happen before subclass constructors finish. However, we won't have set the
-            // drawable as visible until the view becomes attached. This guard below keeps
-            // multiple calls to this method from constructors from causing issues.
-            if (mBackground.isVisible()) {
+            if (isAttachedToWindow()) {
                 mBackground.setVisible(false, false);
             }
             mBackground.setCallback(null);
@@ -18311,13 +18329,7 @@
         }
 
         if (mForegroundInfo.mDrawable != null) {
-            // It's possible for this method to be invoked from the View constructor before
-            // subclass constructors have run. Drawables can and should trigger invalidations
-            // and other activity with their callback on visibility changes, which shouldn't
-            // happen before subclass constructors finish. However, we won't have set the
-            // drawable as visible until the view becomes attached. This guard below keeps
-            // multiple calls to this method from constructors from causing issues.
-            if (mForegroundInfo.mDrawable.isVisible()) {
+            if (isAttachedToWindow()) {
                 mForegroundInfo.mDrawable.setVisible(false, false);
             }
             mForegroundInfo.mDrawable.setCallback(null);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f695873..3f7bbdf 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3251,8 +3251,11 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
-    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
+    public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
         int count = mChildrenCount;
         int[] visibilities = null;
 
@@ -3262,7 +3265,8 @@
                 View child = getChildAt(i);
                 visibilities[i] = child.getVisibility();
                 if (visibilities[i] == View.VISIBLE) {
-                    child.setVisibility(INVISIBLE);
+                    child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
+                            | (View.INVISIBLE & View.VISIBILITY_MASK);
                 }
             }
         }
@@ -3271,7 +3275,9 @@
 
         if (skipChildren) {
             for (int i = 0; i < count; i++) {
-                getChildAt(i).setVisibility(visibilities[i]);
+                View child = getChildAt(i);
+                child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
+                        | (visibilities[i] & View.VISIBILITY_MASK);
             }
         }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index c5b8849..c604234 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -1110,9 +1110,6 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             mView.setHasTransientState(false);
-            if (mListener != null) {
-                mListener.onAnimationEnd(animation);
-            }
             if (mAnimatorCleanupMap != null) {
                 Runnable r = mAnimatorCleanupMap.get(animation);
                 if (r != null) {
@@ -1120,6 +1117,9 @@
                 }
                 mAnimatorCleanupMap.remove(animation);
             }
+            if (mListener != null) {
+                mListener.onAnimationEnd(animation);
+            }
             if (mAnimatorOnEndMap != null) {
                 Runnable r = mAnimatorOnEndMap.get(animation);
                 if (r != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5d4ee874..5b2877f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -774,7 +774,7 @@
      *                          has invoked. If false, the functor may be invoked
      *                          asynchronously.
      */
-    public void invokeFunctor(long functor, boolean waitForCompletion) {
+    public static void invokeFunctor(long functor, boolean waitForCompletion) {
         ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
     }
 
@@ -3415,6 +3415,13 @@
                         updateConfiguration(config, false);
                     }
 
+                    final boolean framesChanged = !mWinFrame.equals(args.arg1)
+                            || !mPendingOverscanInsets.equals(args.arg5)
+                            || !mPendingContentInsets.equals(args.arg2)
+                            || !mPendingStableInsets.equals(args.arg6)
+                            || !mPendingVisibleInsets.equals(args.arg3)
+                            || !mPendingOutsets.equals(args.arg7);
+
                     mWinFrame.set((Rect) args.arg1);
                     mPendingOverscanInsets.set((Rect) args.arg5);
                     mPendingContentInsets.set((Rect) args.arg2);
@@ -3431,7 +3438,7 @@
                         mReportNextDraw = true;
                     }
 
-                    if (mView != null) {
+                    if (mView != null && framesChanged) {
                         forceLayout(mView);
                     }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 36ee3e6..2f3f0bf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -298,7 +298,7 @@
 
     private boolean mDestroyed;
 
-    private boolean mOverlayWithDecorCaption = false;
+    private boolean mOverlayWithDecorCaptionEnabled = false;
 
     // The current window attributes.
     private final WindowManager.LayoutParams mWindowAttributes =
@@ -2139,13 +2139,13 @@
      * down. This affects only freeform windows since they display the caption.
      * @hide
      */
-    public void setOverlayDecorCaption(boolean overlayCaption) {
-        mOverlayWithDecorCaption = overlayCaption;
+    public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
+        mOverlayWithDecorCaptionEnabled = enabled;
     }
 
     /** @hide */
-    public boolean getOverlayDecorCaption() {
-        return mOverlayWithDecorCaption;
+    public boolean isOverlayWithDecorCaptionEnabled() {
+        return mOverlayWithDecorCaptionEnabled;
     }
 
     /** @hide */
@@ -2181,7 +2181,7 @@
      * Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
      * @hide
      */
-    public abstract void onMultiWindowChanged();
+    public abstract void onMultiWindowModeChanged();
 
     /**
      * Called when the activity just relaunched.
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index b721074..737e4607 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -44,6 +44,8 @@
     public boolean focused;
     public final Rect boundsInScreen = new Rect();
     public List<IBinder> childTokens;
+    public CharSequence title;
+    public int accessibilityIdOfAnchor = View.NO_ID;
 
     private WindowInfo() {
         /* do nothing - hide constructor */
@@ -65,6 +67,8 @@
         window.parentToken = other.parentToken;
         window.focused = other.focused;
         window.boundsInScreen.set(other.boundsInScreen);
+        window.title = other.title;
+        window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
 
         if (other.childTokens != null && !other.childTokens.isEmpty()) {
             if (window.childTokens == null) {
@@ -95,6 +99,8 @@
         parcel.writeStrongBinder(parentToken);
         parcel.writeInt(focused ? 1 : 0);
         boundsInScreen.writeToParcel(parcel, flags);
+        parcel.writeCharSequence(title);
+        parcel.writeInt(accessibilityIdOfAnchor);
 
         if (childTokens != null && !childTokens.isEmpty()) {
             parcel.writeInt(1);
@@ -108,13 +114,15 @@
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("WindowInfo[");
-        builder.append("type=").append(type);
+        builder.append("title=").append(title);
+        builder.append(", type=").append(type);
         builder.append(", layer=").append(layer);
         builder.append(", token=").append(token);
         builder.append(", bounds=").append(boundsInScreen);
         builder.append(", parent=").append(parentToken);
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
+        builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
         builder.append(']');
         return builder.toString();
     }
@@ -126,6 +134,8 @@
         parentToken = parcel.readStrongBinder();
         focused = (parcel.readInt() == 1);
         boundsInScreen.readFromParcel(parcel);
+        title = parcel.readCharSequence();
+        accessibilityIdOfAnchor = parcel.readInt();
 
         final boolean hasChildren = (parcel.readInt() == 1);
         if (hasChildren) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 03dcf99..c372c30 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1693,6 +1693,14 @@
          */
         public long userActivityTimeout = -1;
 
+        /**
+         * For windows with an anchor (e.g. PopupWindow), keeps track of the View that anchors the
+         * window.
+         *
+         * @hide
+         */
+        public int accessibilityIdOfAnchor = -1;
+
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = TYPE_APPLICATION;
@@ -1799,6 +1807,7 @@
             out.writeInt(surfaceInsets.bottom);
             out.writeInt(hasManualSurfaceInsets ? 1 : 0);
             out.writeInt(needsMenuKey);
+            out.writeInt(accessibilityIdOfAnchor);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1849,6 +1858,7 @@
             surfaceInsets.bottom = in.readInt();
             hasManualSurfaceInsets = in.readInt() != 0;
             needsMenuKey = in.readInt();
+            accessibilityIdOfAnchor = in.readInt();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1888,6 +1898,8 @@
         /** {@hide} */
         public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
         /** {@hide} */
+        public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
+        /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
         // internal buffer to backup/restore parameters under compatibility mode.
@@ -2048,6 +2060,11 @@
                 changes |= NEEDS_MENU_KEY_CHANGED;
             }
 
+            if (accessibilityIdOfAnchor != o.accessibilityIdOfAnchor) {
+                accessibilityIdOfAnchor = o.accessibilityIdOfAnchor;
+                changes |= ACCESSIBILITY_ANCHOR_CHANGED;
+            }
+
             return changes;
         }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c1392fe..23b0df2 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -415,7 +415,7 @@
          * Returns true if the window is current in multi-windowing mode. i.e. it shares the
          * screen with other application windows.
          */
-        public boolean inMultiWindowMode();
+        public boolean isInMultiWindowMode();
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 2cde03d..f8a13a3 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -240,10 +240,12 @@
  *   <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
  *       was traversed.</li>
  *   <li>{@link #getText()} -  The text of the source's sub-tree.</li>
- *   <li>{@link #getFromIndex()} - The start of the next/previous text at the specified granularity
- *           - inclusive.</li>
- *   <li>{@link #getToIndex()} - The end of the next/previous text at the specified granularity
- *           - exclusive.</li>
+ *   <li>{@link #getFromIndex()} - The start the text that was skipped over in this movement.
+ *       This is the starting point when moving forward through the text, but not when moving
+ *       back.</li>
+ *   <li>{@link #getToIndex()} - The end of the text that was skipped over in this movement.
+ *       This is the ending point when moving forward through the text, but not when moving
+ *       back.</li>
  *   <li>{@link #isPassword()} - Whether the source is password.</li>
  *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
  *   <li>{@link #getContentDescription()} - The content description of the source.</li>
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ad78b68..d0d4507 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -89,6 +89,8 @@
     private int mParentId = UNDEFINED;
     private final Rect mBoundsInScreen = new Rect();
     private LongArray mChildIds;
+    private CharSequence mTitle;
+    private int mAnchorId = UNDEFINED;
 
     private int mConnectionId = UNDEFINED;
 
@@ -97,6 +99,26 @@
     }
 
     /**
+     * Gets the title of the window.
+     *
+     * @return The title.
+     */
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Sets the title of the window.
+     *
+     * @param title The title.
+     *
+     * @hide
+     */
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+    }
+
+    /**
      * Gets the type of the window.
      *
      * @return The type.
@@ -159,9 +181,35 @@
     }
 
     /**
-     * Gets the parent window if such.
+     * Sets the anchor node's ID.
      *
-     * @return The parent window.
+     * @param anchorId The anchor's accessibility id in its window.
+     *
+     * @hide
+     */
+    public void setAnchorId(int anchorId) {
+        mAnchorId = anchorId;
+    }
+
+    /**
+     * Gets the node that anchors this window to another.
+     *
+     * @return The anchor node, or {@code null} if none exists.
+     */
+    public AccessibilityNodeInfo getAnchor() {
+        if ((mConnectionId == UNDEFINED) || (mAnchorId == UNDEFINED) || (mParentId == UNDEFINED)) {
+            return null;
+        }
+
+        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+                mParentId, mAnchorId, true, 0);
+    }
+
+    /**
+     * Gets the parent window.
+     *
+     * @return The parent window, or {@code null} if none exists.
      */
     public AccessibilityWindowInfo getParent() {
         if (mConnectionId == UNDEFINED || mParentId == UNDEFINED) {
@@ -370,6 +418,8 @@
         infoClone.mId = info.mId;
         infoClone.mParentId = info.mParentId;
         infoClone.mBoundsInScreen.set(info.mBoundsInScreen);
+        infoClone.mTitle = info.mTitle;
+        infoClone.mAnchorId = info.mAnchorId;
 
         if (info.mChildIds != null && info.mChildIds.size() > 0) {
             if (infoClone.mChildIds == null) {
@@ -410,6 +460,8 @@
         parcel.writeInt(mId);
         parcel.writeInt(mParentId);
         mBoundsInScreen.writeToParcel(parcel, flags);
+        parcel.writeCharSequence(mTitle);
+        parcel.writeInt(mAnchorId);
 
         final LongArray childIds = mChildIds;
         if (childIds == null) {
@@ -432,6 +484,8 @@
         mId = parcel.readInt();
         mParentId = parcel.readInt();
         mBoundsInScreen.readFromParcel(parcel);
+        mTitle = parcel.readCharSequence();
+        mAnchorId = parcel.readInt();
 
         final int childCount = parcel.readInt();
         if (childCount > 0) {
@@ -471,6 +525,7 @@
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("AccessibilityWindowInfo[");
+        builder.append("title=").append(mTitle);
         builder.append("id=").append(mId);
         builder.append(", type=").append(typeToString(mType));
         builder.append(", layer=").append(mLayer);
@@ -494,6 +549,7 @@
             builder.append(']');
         } else {
             builder.append(", hasParent=").append(mParentId != UNDEFINED);
+            builder.append(", isAnchored=").append(mAnchorId != UNDEFINED);
             builder.append(", hasChildren=").append(mChildIds != null
                     && mChildIds.size() > 0);
         }
@@ -515,6 +571,8 @@
             mChildIds.clear();
         }
         mConnectionId = UNDEFINED;
+        mAnchorId = UNDEFINED;
+        mTitle = null;
     }
 
     /**
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a3c49c5..89dec2d 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import android.annotation.CallSuper;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Bundle;
@@ -154,12 +155,11 @@
     }
 
     /**
-     * Called when this InputConnection is no longer used by the InputMethodManager.
-     *
-     * @hide
+     * Default implementation calls {@link #finishComposingText()}.
      */
-    public void reportFinish() {
-        // Intentionally empty
+    @CallSuper
+    public void closeConnection() {
+        finishComposingText();
     }
 
     /**
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 8002a8e..9f66429 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -45,6 +45,8 @@
  *     was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
  *     <li>{@link #getHandler()}}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#N}.</li>
+ *     <li>{@link #closeConnection()}}, which was introduced in
+ *     {@link android.os.Build.VERSION_CODES#N}.</li>
  * </ul>
  *
  * <h3>Implementing an IME or an editor</h3>
@@ -820,4 +822,18 @@
      * @return {@code null} to use the default {@link Handler}.
      */
     public Handler getHandler();
+
+    /**
+     * Called by the system up to only once to notify that the system is about to invalidate
+     * connection between the input method and the application.
+     *
+     * <p><strong>Editor authors</strong>: You can clear all the nested batch edit right now and
+     * you no longer need to handle subsequent callbacks on this connection, including
+     * {@link #beginBatchEdit()}}.  Note that although the system tries to call this method whenever
+     * possible, there may be a chance that this method is not called in some exceptional
+     * situations.</p>
+     *
+     * <p>Note: This does nothing when called from input methods.</p>
+     */
+    public void closeConnection();
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
index 46b2c3e..118a61f 100644
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -73,6 +73,11 @@
          * {@link android.os.Build.VERSION_CODES#N} and later.
          */
         int GET_HANDLER = 1 << 5;
+        /**
+         * {@link InputConnection#closeConnection()}} is available in
+         * {@link android.os.Build.VERSION_CODES#N} and later.
+         */
+        int CLOSE_CONNECTION = 1 << 6;
     }
 
     private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
@@ -119,6 +124,9 @@
         if (!hasGetHandler(clazz)) {
             flags |= MissingMethodFlags.GET_HANDLER;
         }
+        if (!hasCloseConnection(clazz)) {
+            flags |= MissingMethodFlags.CLOSE_CONNECTION;
+        }
         sMissingMethodsMap.put(clazz, flags);
         return flags;
     }
@@ -178,6 +186,15 @@
         }
     }
 
+    private static boolean hasCloseConnection(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("closeConnection");
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
     public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
         final StringBuilder sb = new StringBuilder();
         boolean isEmpty = true;
@@ -219,6 +236,12 @@
             }
             sb.append("getHandler()");
         }
+        if ((flags & MissingMethodFlags.CLOSE_CONNECTION) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("closeConnection()");
+        }
         return sb.toString();
     }
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 381df49..e743f62 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -261,4 +261,12 @@
     public Handler getHandler() {
         return mTarget.getHandler();
     }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
+    public void closeConnection() {
+        mTarget.closeConnection();
+    }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f5908a5..6879901 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -544,7 +544,7 @@
                 // reportFinish() will take effect.
                 return;
             }
-            reportFinish();
+            closeConnection();
         }
 
         @Override
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 94dc03c..b6516c8 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -16,6 +16,8 @@
 
 package android.webkit;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -86,8 +88,7 @@
      */
     public void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
             boolean waitForCompletion) {
-        ViewRootImpl viewRootImpl = containerView.getViewRootImpl();
-        viewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
+        ViewRootImpl.invokeFunctor(nativeDrawGLFunctor, waitForCompletion);
     }
 
     /**
@@ -110,6 +111,24 @@
     }
 
     /**
+     * Set the Runnable callback the DrawGlFunction functor is detached and free to be destroyed.
+     * This will replace the previous callback, if any.
+     *
+     * @param view The view to set the callback. Should be the view where onDraw inserted
+     *        DrawGLFunctor.
+     * @param callback The new callback to set on the view.
+     * @throws IllegalArgumentException if view is null.
+     * @return The previous callback on this view.
+     */
+    public Runnable setDrawGlFunctionDetachedCallback(
+        @NonNull View view, @Nullable Runnable callback) {
+        if (view == null) {
+            throw new IllegalArgumentException("View cannot be null");
+        }
+        return view.setRenderNodeDetachedCallback(callback);
+    }
+
+    /**
      * Detaches the draw GL functor.
      *
      * @param nativeDrawGLFunctor the pointer to the native functor that implements
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index d884f19..0ac5731 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -21,7 +21,6 @@
 import android.app.AppGlobals;
 import android.app.Application;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -561,20 +560,12 @@
         return result;
     }
 
-    /**
-     * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
-     * than just one of its components).
-     * @hide
-     */
-    public static boolean entirePackageChanged(Intent intent) {
-        String[] componentList =
-            intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
-        return Arrays.asList(componentList).contains(
-                intent.getDataString().substring("package:".length()));
-    }
+    private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
 
-    private static IWebViewUpdateService getUpdateService() {
-        return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+    /** @hide */
+    public static IWebViewUpdateService getUpdateService() {
+        return IWebViewUpdateService.Stub.asInterface(
+                ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
     }
 
     private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 75ccf35..5d091c9 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -16,32 +16,20 @@
 
 package android.webkit;
 
-import android.app.AppGlobals;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.os.Build;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.AndroidRuntimeException;
-import android.util.Base64;
 
 import java.util.Arrays;
 
-/** @hide */
-public class WebViewProviderInfo implements Parcelable {
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewProviderInfo implements Parcelable {
 
-    /**
-     * @hide
-     */
-    public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
-        public WebViewPackageNotFoundException(String message) { super(message); }
-        public WebViewPackageNotFoundException(Exception e) { super(e); }
-    }
-
-    public WebViewProviderInfo(String packageName, String description, boolean availableByDefault,
-            boolean isFallback, String[] signatures) {
+    public WebViewProviderInfo(String packageName, String description,
+            boolean availableByDefault, boolean isFallback, String[] signatures) {
         this.packageName = packageName;
         this.description = description;
         this.availableByDefault = availableByDefault;
@@ -49,92 +37,6 @@
         this.signatures = signatures;
     }
 
-    private boolean hasValidSignature() {
-        if (Build.IS_DEBUGGABLE)
-            return true;
-        Signature[] packageSignatures;
-        try {
-            // If no signature is declared, instead check whether the package is included in the
-            // system.
-            if (signatures == null || signatures.length == 0)
-                return getPackageInfo().applicationInfo.isSystemApp();
-
-            packageSignatures = getPackageInfo().signatures;
-        } catch (WebViewPackageNotFoundException e) {
-            return false;
-        }
-        if (packageSignatures.length != 1)
-            return false;
-
-        final byte[] packageSignature = packageSignatures[0].toByteArray();
-        // Return whether the package signature matches any of the valid signatures
-        for (String signature : signatures) {
-            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
-            if (Arrays.equals(packageSignature, validSignature))
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns whether this provider is valid for use as a WebView provider.
-     */
-    public boolean isValidProvider() {
-        ApplicationInfo applicationInfo;
-        try {
-            applicationInfo = getPackageInfo().applicationInfo;
-        } catch (WebViewPackageNotFoundException e) {
-            return false;
-        }
-        if (hasValidSignature() && WebViewFactory.getWebViewLibrary(applicationInfo) != null) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns whether this package is enabled.
-     * This state can be changed by the user from Settings->Apps
-     */
-    public boolean isEnabled() {
-        try {
-            // Explicitly fetch up-to-date package info here since the enabled-state of the package
-            // might have changed since we last fetched its package info.
-            updatePackageInfo();
-            return getPackageInfo().applicationInfo.enabled;
-        } catch (WebViewPackageNotFoundException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Returns whether the provider is always available as long as it is valid.
-     * If this returns false, the provider will only be used if the user chose this provider.
-     */
-    public boolean isAvailableByDefault() {
-        return availableByDefault;
-    }
-
-    public boolean isFallbackPackage() {
-        return isFallback;
-    }
-
-    private void updatePackageInfo() {
-        try {
-            PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-            packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new WebViewPackageNotFoundException(e);
-        }
-    }
-
-    public PackageInfo getPackageInfo() {
-        if (packageInfo == null) {
-            updatePackageInfo();
-        }
-        return packageInfo;
-    }
-
     // aidl stuff
     public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
         new Parcelable.Creator<WebViewProviderInfo>() {
@@ -153,7 +55,6 @@
         availableByDefault = (in.readInt() > 0);
         isFallback = (in.readInt() > 0);
         signatures = in.createStringArray();
-        packageInfo = null;
     }
 
     @Override
@@ -171,16 +72,9 @@
     }
 
     // fields read from framework resource
-    public String packageName;
-    public String description;
-    private boolean availableByDefault;
-    private boolean isFallback;
-
-    private String[] signatures;
-
-    private PackageInfo packageInfo;
-
-    // flags declaring we want extra info from the package manager
-    private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
-            | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+    public final String packageName;
+    public final String description;
+    public final boolean availableByDefault;
+    public final boolean isFallback;
+    public final String[] signatures;
 }
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
new file mode 100644
index 0000000..4e83d88
--- /dev/null
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -0,0 +1,66 @@
+/*
+ * 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.webkit;
+
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class WebViewUpdateService {
+
+    private WebViewUpdateService () {}
+
+    /**
+     * Fetch all packages that could potentially implement WebView.
+     */
+    public static WebViewProviderInfo[] getAllWebViewPackages() {
+        try {
+            return getUpdateService().getAllWebViewPackages();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Fetch all packages that could potentially implement WebView and are currently valid.
+     */
+    public static WebViewProviderInfo[] getValidWebViewPackages() {
+        try {
+            return getUpdateService().getValidWebViewPackages();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
+     */
+    public static String getCurrentWebViewPackageName() {
+        try {
+            return getUpdateService().getCurrentWebViewPackageName();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static IWebViewUpdateService getUpdateService() {
+        return WebViewFactory.getUpdateService();
+    }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7cbe8de..6e1dff9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -5937,6 +5937,11 @@
         public Handler getHandler() {
             return getTarget().getHandler();
         }
+
+        @Override
+        public void closeConnection() {
+            getTarget().closeConnection();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/AccessibilityIterators.java b/core/java/android/widget/AccessibilityIterators.java
index a3d58a4..442ffa1 100644
--- a/core/java/android/widget/AccessibilityIterators.java
+++ b/core/java/android/widget/AccessibilityIterators.java
@@ -134,8 +134,8 @@
 
         @Override
         public int[] following(int offset) {
-            final int textLegth = mText.length();
-            if (textLegth <= 0) {
+            final int textLength = mText.length();
+            if (textLength <= 0) {
                 return null;
             }
             if (offset >= mText.length()) {
@@ -163,8 +163,8 @@
 
         @Override
         public int[] preceding(int offset) {
-            final int textLegth = mText.length();
-            if (textLegth <= 0) {
+            final int textLength = mText.length();
+            if (textLength <= 0) {
                 return null;
             }
             if (offset <= 0) {
@@ -181,8 +181,13 @@
             final int pageHeight = mTempRect.height() - mView.getTotalPaddingTop()
                     - mView.getTotalPaddingBottom();
             final int previousPageEndY = currentLineTop - pageHeight;
-            final int currentPageStartLine = (previousPageEndY > 0) ?
-                     mLayout.getLineForVertical(previousPageEndY) + 1 : 0;
+            int currentPageStartLine = (previousPageEndY > 0) ?
+                     mLayout.getLineForVertical(previousPageEndY) : 0;
+            // If we're at the end of text, we're at the end of the current line rather than the
+            // start of the next line, so we should move up one fewer lines than we would otherwise.
+            if (end == mText.length() && (currentPageStartLine < currentLine)) {
+                currentPageStartLine += 1;
+            }
 
             final int start = getLineEdgeIndex(currentPageStartLine, DIRECTION_START);
 
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 027f6d6..9d228cf 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -20,6 +20,7 @@
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
@@ -61,17 +62,13 @@
 
     private final LayoutInflater mInflater;
 
-    /**
-     * Contains the list of objects that represent the data of this ArrayAdapter.
-     * The content of this list is referred to as "the array" in the documentation.
-     */
-    private List<T> mObjects;
+    private final Context mContext;
 
     /**
      * The resource indicating what views to inflate to display the content of this
      * array adapter.
      */
-    private int mResource;
+    private final int mResource;
 
     /**
      * The resource indicating what views to inflate to display the content of this
@@ -80,7 +77,13 @@
     private int mDropDownResource;
 
     /**
-     * If the inflated resource is not a TextView, {@link #mFieldId} is used to find
+     * Contains the list of objects that represent the data of this ArrayAdapter.
+     * The content of this list is referred to as "the array" in the documentation.
+     */
+    private List<T> mObjects;
+
+    /**
+     * If the inflated resource is not a TextView, {@code mFieldId} is used to find
      * a TextView inside the inflated views hierarchy. This field must contain the
      * identifier that matches the one defined in the resource file.
      */
@@ -92,8 +95,6 @@
      */
     private boolean mNotifyOnChange = true;
 
-    private Context mContext;
-
     // A copy of the original mObjects array, initialized from and then used instead as soon as
     // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
     private ArrayList<T> mOriginalValues;
@@ -109,8 +110,8 @@
      * @param resource The resource ID for a layout file containing a TextView to use when
      *                 instantiating views.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource) {
-        this(context, resource, 0, new ArrayList<T>());
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource) {
+        this(context, resource, 0, new ArrayList<>());
     }
 
     /**
@@ -121,8 +122,9 @@
      *                 instantiating views.
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
-        this(context, resource, textViewResourceId, new ArrayList<T>());
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @IdRes int textViewResourceId) {
+        this(context, resource, textViewResourceId, new ArrayList<>());
     }
 
     /**
@@ -133,7 +135,7 @@
      *                 instantiating views.
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {
         this(context, resource, 0, Arrays.asList(objects));
     }
 
@@ -146,8 +148,8 @@
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
-            @NonNull T[] objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @IdRes int textViewResourceId, @NonNull T[] objects) {
         this(context, resource, textViewResourceId, Arrays.asList(objects));
     }
 
@@ -159,7 +161,8 @@
      *                 instantiating views.
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @NonNull List<T> objects) {
         this(context, resource, 0, objects);
     }
 
@@ -172,8 +175,8 @@
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
-            @NonNull List<T> objects) {
+    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+            @IdRes int textViewResourceId, @NonNull List<T> objects) {
         mContext = context;
         mInflater = LayoutInflater.from(context);
         mResource = mDropDownResource = resource;
@@ -186,7 +189,7 @@
      *
      * @param object The object to add at the end of the array.
      */
-    public void add(T object) {
+    public void add(@Nullable T object) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.add(object);
@@ -201,8 +204,17 @@
      * Adds the specified Collection at the end of the array.
      *
      * @param collection The Collection to add at the end of the array.
+     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
      */
-    public void addAll(Collection<? extends T> collection) {
+    public void addAll(@NonNull Collection<? extends T> collection) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.addAll(collection);
@@ -235,7 +247,7 @@
      * @param object The object to insert into the array.
      * @param index The index at which the object must be inserted.
      */
-    public void insert(T object, int index) {
+    public void insert(@Nullable T object, int index) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.add(index, object);
@@ -251,7 +263,7 @@
      *
      * @param object The object to remove.
      */
-    public void remove(T object) {
+    public void remove(@Nullable T object) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 mOriginalValues.remove(object);
@@ -282,7 +294,7 @@
      * @param comparator The comparator used to sort the objects contained
      *        in this adapter.
      */
-    public void sort(Comparator<? super T> comparator) {
+    public void sort(@NonNull Comparator<? super T> comparator) {
         synchronized (mLock) {
             if (mOriginalValues != null) {
                 Collections.sort(mOriginalValues, comparator);
@@ -293,9 +305,6 @@
         if (mNotifyOnChange) notifyDataSetChanged();
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void notifyDataSetChanged() {
         super.notifyDataSetChanged();
@@ -326,21 +335,17 @@
      *
      * @return The Context associated with this adapter.
      */
-    public Context getContext() {
+    public @NonNull Context getContext() {
         return mContext;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public int getCount() {
         return mObjects.size();
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public T getItem(int position) {
+    @Override
+    public @Nullable T getItem(int position) {
         return mObjects.get(position);
     }
 
@@ -351,28 +356,25 @@
      *
      * @return The position of the specified item.
      */
-    public int getPosition(T item) {
+    public int getPosition(@Nullable T item) {
         return mObjects.indexOf(item);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public long getItemId(int position) {
         return position;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public View getView(int position, View convertView, ViewGroup parent) {
+    @Override
+    public @NonNull View getView(int position, @Nullable View convertView,
+            @NonNull ViewGroup parent) {
         return createViewFromResource(mInflater, position, convertView, parent, mResource);
     }
 
-    private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
-            ViewGroup parent, int resource) {
-        View view;
-        TextView text;
+    private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
+            @Nullable View convertView, @NonNull ViewGroup parent, int resource) {
+        final View view;
+        final TextView text;
 
         if (convertView == null) {
             view = inflater.inflate(resource, parent, false);
@@ -387,6 +389,12 @@
             } else {
                 //  Otherwise, find the TextView field within the layout
                 text = (TextView) view.findViewById(mFieldId);
+
+                if (text == null) {
+                    throw new RuntimeException("Failed to find view with ID "
+                            + mContext.getResources().getResourceName(mFieldId)
+                            + " in item layout");
+                }
             }
         } catch (ClassCastException e) {
             Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
@@ -394,9 +402,9 @@
                     "ArrayAdapter requires the resource ID to be a TextView", e);
         }
 
-        T item = getItem(position);
+        final T item = getItem(position);
         if (item instanceof CharSequence) {
-            text.setText((CharSequence)item);
+            text.setText((CharSequence) item);
         } else {
             text.setText(item.toString());
         }
@@ -426,7 +434,7 @@
      * @see #getDropDownView(int, View, ViewGroup)
      */
     @Override
-    public void setDropDownViewTheme(Resources.Theme theme) {
+    public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
         if (theme == null) {
             mDropDownInflater = null;
         } else if (theme == mInflater.getContext().getTheme()) {
@@ -438,12 +446,13 @@
     }
 
     @Override
-    public Resources.Theme getDropDownViewTheme() {
+    public @Nullable Resources.Theme getDropDownViewTheme() {
         return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
     }
 
     @Override
-    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+    public View getDropDownView(int position, @Nullable View convertView,
+            @NonNull ViewGroup parent) {
         final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
         return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
     }
@@ -458,16 +467,14 @@
      *
      * @return An ArrayAdapter<CharSequence>.
      */
-    public static ArrayAdapter<CharSequence> createFromResource(Context context,
+    public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,
             @ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
-        CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
-        return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
+        final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
+        return new ArrayAdapter<>(context, textViewResId, strings);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public Filter getFilter() {
+    @Override
+    public @NonNull Filter getFilter() {
         if (mFilter == null) {
             mFilter = new ArrayFilter();
         }
@@ -482,31 +489,31 @@
     private class ArrayFilter extends Filter {
         @Override
         protected FilterResults performFiltering(CharSequence prefix) {
-            FilterResults results = new FilterResults();
+            final FilterResults results = new FilterResults();
 
             if (mOriginalValues == null) {
                 synchronized (mLock) {
-                    mOriginalValues = new ArrayList<T>(mObjects);
+                    mOriginalValues = new ArrayList<>(mObjects);
                 }
             }
 
             if (prefix == null || prefix.length() == 0) {
-                ArrayList<T> list;
+                final ArrayList<T> list;
                 synchronized (mLock) {
-                    list = new ArrayList<T>(mOriginalValues);
+                    list = new ArrayList<>(mOriginalValues);
                 }
                 results.values = list;
                 results.count = list.size();
             } else {
-                String prefixString = prefix.toString().toLowerCase();
+                final String prefixString = prefix.toString().toLowerCase();
 
-                ArrayList<T> values;
+                final ArrayList<T> values;
                 synchronized (mLock) {
-                    values = new ArrayList<T>(mOriginalValues);
+                    values = new ArrayList<>(mOriginalValues);
                 }
 
                 final int count = values.size();
-                final ArrayList<T> newValues = new ArrayList<T>();
+                final ArrayList<T> newValues = new ArrayList<>();
 
                 for (int i = 0; i < count; i++) {
                     final T value = values.get(i);
@@ -517,11 +524,8 @@
                         newValues.add(value);
                     } else {
                         final String[] words = valueText.split(" ");
-                        final int wordCount = words.length;
-
-                        // Start at index 0, in case valueText starts with space(s)
-                        for (int k = 0; k < wordCount; k++) {
-                            if (words[k].startsWith(prefixString)) {
+                        for (String word : words) {
+                            if (word.startsWith(prefixString)) {
                                 newValues.add(value);
                                 break;
                             }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 6e3dbd8..e3357a7 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -75,8 +75,6 @@
  */
 @Widget
 public class DatePicker extends FrameLayout {
-    private static final String LOG_TAG = DatePicker.class.getSimpleName();
-
     private static final int MODE_SPINNER = 1;
     private static final int MODE_CALENDAR = 2;
 
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 5adac01..332e89c 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -378,9 +378,9 @@
         mCurrentDate.set(Calendar.MONTH, monthOfYear);
         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
 
-        mDateChangedListener = callBack;
-
         onDateChanged(false, false);
+
+        mDateChangedListener = callBack;
     }
 
     @Override
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 255de79..d8a3c56 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -244,6 +244,7 @@
         setDate(year, monthOfYear, dayOfMonth);
         updateSpinners();
         updateCalendarView();
+
         mOnDateChangedListener = onDateChangedListener;
     }
 
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 434e3eb..ad35550 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -155,6 +155,9 @@
     public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+                if (!isEnabled()) {
+                    return false;
+                }
                 CharSequence text = (arguments != null) ? arguments.getCharSequence(
                         AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
                 setText(text);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 59d857c..47b0348 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3640,6 +3640,9 @@
             }
 
             if (menu.hasVisibleItems() || mode.getCustomView() != null) {
+                if (mHasSelection && !mTextView.hasTransientState()) {
+                    mTextView.setHasTransientState(true);
+                }
                 return true;
             } else {
                 return false;
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index fe8916b..9ac4917 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -16,17 +16,15 @@
 
 package android.widget;
 
-import java.util.ArrayList;
+import com.android.internal.R;
 
+import android.annotation.AttrRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
@@ -36,8 +34,7 @@
 import android.view.ViewHierarchyEncoder;
 import android.widget.RemoteViews.RemoteView;
 
-import com.android.internal.R;
-
+import java.util.ArrayList;
 
 /**
  * FrameLayout is designed to block out an area on the screen to display
@@ -75,31 +72,29 @@
     @ViewDebug.ExportedProperty(category = "padding")
     private int mForegroundPaddingBottom = 0;
 
-    private final Rect mSelfBounds = new Rect();
-    private final Rect mOverlayBounds = new Rect();
-    
-    private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1);
-    
-    public FrameLayout(Context context) {
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+    public FrameLayout(@NonNull Context context) {
         super(context);
     }
-    
-    public FrameLayout(Context context, @Nullable AttributeSet attrs) {
+
+    public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+    public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public FrameLayout(
-            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes);
-        
-        if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) {
+                attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
+
+        if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
             setMeasureAllChildren(true);
         }
 
@@ -171,10 +166,6 @@
             mPaddingBottom + mForegroundPaddingBottom;
     }
 
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int count = getChildCount();
@@ -264,17 +255,13 @@
             }
         }
     }
- 
-    /**
-     * {@inheritDoc}
-     */
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         layoutChildren(left, top, right, bottom, false /* no force left gravity */);
     }
 
-    void layoutChildren(int left, int top, int right, int bottom,
-                                  boolean forceLeftGravity) {
+    void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
         final int count = getChildCount();
 
         final int parentLeft = getPaddingLeftWithForeground();
@@ -378,12 +365,9 @@
         return mMeasureAllChildren;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new FrameLayout.LayoutParams(getContext(), attrs);        
+        return new FrameLayout.LayoutParams(getContext(), attrs);
     }
 
     @Override
@@ -391,9 +375,6 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return p instanceof LayoutParams;
@@ -431,34 +412,30 @@
      * Per-child layout information for layouts that support margins.
      * See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes}
      * for a list of all child view attributes that this class supports.
-     * 
+     *
      * @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
      */
     public static class LayoutParams extends MarginLayoutParams {
         /**
          * The gravity to apply with the View to which these layout parameters
          * are associated.
+         * <p>
+         * The default value is {@code Gravity.TOP | Gravity.START}
          *
          * @see android.view.Gravity
-         * 
          * @attr ref android.R.styleable#FrameLayout_Layout_layout_gravity
          */
-        public int gravity = -1;
+        public int gravity = DEFAULT_CHILD_GRAVITY;
 
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(Context c, AttributeSet attrs) {
+        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
             super(c, attrs);
 
-            TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout_Layout);
-            gravity = a.getInt(com.android.internal.R.styleable.FrameLayout_Layout_layout_gravity, -1);
+            final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FrameLayout_Layout);
+            gravity = a.getInt(R.styleable.FrameLayout_Layout_layout_gravity,
+                    DEFAULT_CHILD_GRAVITY);
             a.recycle();
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public LayoutParams(int width, int height) {
             super(width, height);
         }
@@ -468,9 +445,9 @@
          * and weight.
          *
          * @param width the width, either {@link #MATCH_PARENT},
-         *        {@link #WRAP_CONTENT} or a fixed size in pixels
+         *              {@link #WRAP_CONTENT} or a fixed size in pixels
          * @param height the height, either {@link #MATCH_PARENT},
-         *        {@link #WRAP_CONTENT} or a fixed size in pixels
+         *               {@link #WRAP_CONTENT} or a fixed size in pixels
          * @param gravity the gravity
          *
          * @see android.view.Gravity
@@ -480,17 +457,11 @@
             this.gravity = gravity;
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(ViewGroup.LayoutParams source) {
+        public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
             super(source);
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(ViewGroup.MarginLayoutParams source) {
+        public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
             super(source);
         }
 
@@ -500,7 +471,7 @@
          *
          * @param source The layout params to copy from.
          */
-        public LayoutParams(LayoutParams source) {
+        public LayoutParams(@NonNull LayoutParams source) {
             super(source);
 
             this.gravity = source.gravity;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0206577..222a040 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -911,17 +911,11 @@
         }
 
         if (mDrawable != null) {
-            // It's possible for this method to be invoked from the constructor before
-            // subclass constructors have run. Drawables can and should trigger invalidations
-            // and other activity with their callback on visibility changes, which shouldn't
-            // happen before subclass constructors finish. However, we won't have set the
-            // drawable as visible until the view becomes attached. This guard below keeps
-            // multiple calls to this method from constructors from causing issues.
-            if (mDrawable.isVisible()) {
-                mDrawable.setVisible(false, false);
-            }
             mDrawable.setCallback(null);
             unscheduleDrawable(mDrawable);
+            if (isAttachedToWindow()) {
+                mDrawable.setVisible(false, false);
+            }
         }
 
         mDrawable = d;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 92631da..c471cf3 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1214,6 +1214,7 @@
         final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
                 p.width, p.height, gravity);
         updateAboveAnchor(aboveAnchor);
+        p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
 
         invokePopup(p);
     }
@@ -1984,6 +1985,13 @@
             update = true;
         }
 
+        int newAccessibilityIdOfAnchor =
+                (mAnchor != null) ? mAnchor.get().getAccessibilityViewId() : -1;
+        if (newAccessibilityIdOfAnchor != p.accessibilityIdOfAnchor) {
+            p.accessibilityIdOfAnchor = newAccessibilityIdOfAnchor;
+            update = true;
+        }
+
         if (update) {
             setLayoutDirectionFromAnchor();
             mWindowManager.updateViewLayout(mDecorView, p);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8bd63df..6d2cea6 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.ColorInt;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -228,6 +229,11 @@
 
         public boolean onClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
+            return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID);
+        }
+
+        public boolean onClickHandler(View view, PendingIntent pendingIntent,
+                Intent fillInIntent, int launchStackId) {
             try {
                 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
                 Context context = view.getContext();
@@ -239,6 +245,10 @@
                             0, 0,
                             view.getMeasuredWidth(), view.getMeasuredHeight());
                 }
+
+                if (launchStackId != StackId.INVALID_STACK_ID) {
+                    opts.setLaunchStackId(launchStackId);
+                }
                 context.startIntentSender(
                         pendingIntent.getIntentSender(), fillInIntent,
                         Intent.FLAG_ACTIVITY_NEW_TASK,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4a68d3c..da0768e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2893,6 +2893,11 @@
     public void setTextLocale(@NonNull Locale locale) {
         mLocalesChanged = true;
         mTextPaint.setTextLocale(locale);
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
     }
 
     /**
@@ -2909,6 +2914,11 @@
     public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
         mLocalesChanged = true;
         mTextPaint.setTextLocales(locales);
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
     }
 
     @Override
@@ -2916,6 +2926,11 @@
         super.onConfigurationChanged(newConfig);
         if (!mLocalesChanged) {
             mTextPaint.setTextLocales(LocaleList.getDefault());
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
         }
     }
 
@@ -8274,14 +8289,12 @@
                     newSelEnd = Selection.getSelectionEnd(buf);
                 }
 
-                if (newSelStart == newSelEnd && hasTransientState()) {
-                    setHasTransientState(false);
-                } else if (newSelStart != newSelEnd && !hasTransientState()) {
-                    setHasTransientState(true);
-                }
-
                 if (mEditor != null) {
                     mEditor.refreshTextActionMode();
+                    if (!hasSelection() && mEditor.mTextActionMode == null && hasTransientState()) {
+                        // User generated selection has been removed.
+                        setHasTransientState(false);
+                    }
                 }
                 onSelectionChanged(newSelStart, newSelEnd);
             }
@@ -9081,6 +9094,9 @@
 
         if (mBufferType == BufferType.EDITABLE) {
             info.setEditable(true);
+            if (isEnabled()) {
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
+            }
         }
 
         if (mEditor != null) {
@@ -9212,6 +9228,17 @@
                     }
                 }
             } return false;
+            case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+                if (!isEnabled() || (mBufferType != BufferType.EDITABLE)) {
+                    return false;
+                }
+                CharSequence text = (arguments != null) ? arguments.getCharSequence(
+                        AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
+                setText(text);
+                if (text != null && text.length() > 0) {
+                    Selection.setSelection((Spannable) mText, text.length());
+                }
+            } return true;
             default: {
                 return super.performAccessibilityActionInternal(action, arguments);
             }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 753c069..b7ac600 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -516,9 +516,15 @@
             }
 
             // Only show the divider if we have a title.
-            final View divider;
+            View divider = null;
             if (mMessage != null || mListView != null || hasCustomPanel) {
-                divider = topPanel.findViewById(R.id.titleDivider);
+                if (!hasCustomPanel) {
+                    divider = topPanel.findViewById(R.id.titleDividerNoCustom);
+                }
+                if (divider == null) {
+                    divider = topPanel.findViewById(R.id.titleDivider);
+                }
+
             } else {
                 divider = topPanel.findViewById(R.id.titleDividerTop);
             }
@@ -526,6 +532,17 @@
             if (divider != null) {
                 divider.setVisibility(View.VISIBLE);
             }
+        } else {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
+            }
+        }
+
+        if (mListView instanceof RecycleListView) {
+            ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
         }
 
         // Update scroll indicators as needed.
@@ -861,23 +878,34 @@
     }
 
     public static class RecycleListView extends ListView {
+        private final int mPaddingTopNoTitle;
+        private final int mPaddingBottomNoButtons;
+
         boolean mRecycleOnMeasure = true;
 
         public RecycleListView(Context context) {
-            super(context);
+            this(context, null);
         }
 
         public RecycleListView(Context context, AttributeSet attrs) {
             super(context, attrs);
+
+            final TypedArray ta = context.obtainStyledAttributes(
+                    attrs, R.styleable.RecycleListView);
+            mPaddingBottomNoButtons = ta.getDimensionPixelOffset(
+                    R.styleable.RecycleListView_paddingBottomNoButtons, -1);
+            mPaddingTopNoTitle = ta.getDimensionPixelOffset(
+                    R.styleable.RecycleListView_paddingTopNoTitle, -1);
         }
 
-        public RecycleListView(Context context, AttributeSet attrs, int defStyleAttr) {
-            super(context, attrs, defStyleAttr);
-        }
-
-        public RecycleListView(
-                Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-            super(context, attrs, defStyleAttr, defStyleRes);
+        public void setHasDecor(boolean hasTitle, boolean hasButtons) {
+            if (!hasButtons || !hasTitle) {
+                final int paddingLeft = getPaddingLeft();
+                final int paddingTop = hasTitle ? getPaddingTop() : mPaddingTopNoTitle;
+                final int paddingRight = getPaddingRight();
+                final int paddingBottom = hasButtons ? getPaddingBottom() : mPaddingBottomNoButtons;
+                setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index d8d6e56..a9d5113 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -181,6 +181,7 @@
     public static final class LocaleInfoComparator implements Comparator<LocaleStore.LocaleInfo> {
         private final Collator mCollator;
         private final boolean mCountryMode;
+        private static final String PREFIX_ARABIC = "\u0627\u0644"; // ALEF-LAM, ال
 
         /**
          * Constructor.
@@ -192,6 +193,20 @@
             mCountryMode = countryMode;
         }
 
+        /*
+         * The Arabic collation should ignore Alef-Lam at the beginning (b/26277596)
+         *
+         * We look at the label's locale, not the current system locale.
+         * This is because the name of the Arabic language itself is in Arabic,
+         * and starts with Alef-Lam, no matter what the system locale is.
+         */
+        private String removePrefixForCompare(Locale locale, String str) {
+            if ("ar".equals(locale.getLanguage()) && str.startsWith(PREFIX_ARABIC)) {
+                return str.substring(PREFIX_ARABIC.length());
+            }
+            return str;
+        }
+
         /**
          * Compares its two arguments for order.
          *
@@ -204,9 +219,11 @@
         public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
             // We don't care about the various suggestion types, just "suggested" (!= 0)
             // and "all others" (== 0)
-            if (mCountryMode || (lhs.isSuggested() == rhs.isSuggested())) {
+            if (lhs.isSuggested() == rhs.isSuggested()) {
                 // They are in the same "bucket" (suggested / others), so we compare the text
-                return mCollator.compare(lhs.getLabel(mCountryMode), rhs.getLabel(mCountryMode));
+                return mCollator.compare(
+                        removePrefixForCompare(lhs.getLocale(), lhs.getLabel(mCountryMode)),
+                        removePrefixForCompare(rhs.getLocale(), rhs.getLabel(mCountryMode)));
             } else {
                 // One locale is suggested and one is not, so we put them in different "buckets"
                 return lhs.isSuggested() ? -1 : 1;
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index c4e6675..7803e52 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -31,8 +31,9 @@
     private static boolean sFullyInitialized = false;
 
     public static class LocaleInfo {
-        private static final int SUGGESTION_TYPE_NONE = 0x00;
-        private static final int SUGGESTION_TYPE_SIM = 0x01;
+        private static final int SUGGESTION_TYPE_NONE = 0;
+        private static final int SUGGESTION_TYPE_SIM = 1 << 0;
+        private static final int SUGGESTION_TYPE_CFG = 1 << 1;
 
         private final Locale mLocale;
         private final Locale mParent;
@@ -273,6 +274,22 @@
         final HashSet<String> localizedLocales = new HashSet<>();
         for (String localeId : LocalePicker.getSystemAssetLocales()) {
             LocaleInfo li = new LocaleInfo(localeId);
+            final String country = li.getLocale().getCountry();
+            // All this is to figure out if we should suggest a country
+            if (!country.isEmpty()) {
+                LocaleInfo cachedLocale = null;
+                if (sLocaleCache.containsKey(li.getId())) { // the simple case, e.g. fr-CH
+                    cachedLocale = sLocaleCache.get(li.getId());
+                } else { // e.g. zh-TW localized, zh-Hant-TW in cache
+                    final String langScriptCtry = li.getLangScriptKey() + "-" + country;
+                    if (sLocaleCache.containsKey(langScriptCtry)) {
+                        cachedLocale = sLocaleCache.get(langScriptCtry);
+                    }
+                }
+                if (cachedLocale != null) {
+                    cachedLocale.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CFG;
+                }
+            }
             localizedLocales.add(li.getLangScriptKey());
         }
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0e02ed6..ff680e2 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -243,10 +243,6 @@
             return;
         }
 
-        // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
-        // control of the system bars.
-        getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
-
         final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
         if (rdl != null) {
             rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 98102ea..e2d29e3 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -49,6 +49,7 @@
     private static final int TYPE_HEADER_SUGGESTED = 0;
     private static final int TYPE_HEADER_ALL_OTHERS = 1;
     private static final int TYPE_LOCALE = 2;
+    private static final int MIN_REGIONS_FOR_SUGGESTIONS = 6;
 
     private ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
     private ArrayList<LocaleStore.LocaleInfo> mOriginalLocaleOptions;
@@ -171,7 +172,15 @@
     }
 
     private boolean showHeaders() {
-        if (mCountryMode) { // never show suggestions in country mode
+        // We don't want to show suggestions for locales with very few regions
+        // (e.g. Romanian, with 2 regions)
+        // So we put a (somewhat) arbitrary limit.
+        //
+        // The initial idea was to make that limit dependent on the screen height.
+        // But that would mean rotating the screen could make the suggestions disappear,
+        // as the number of countries that fits on the screen would be different in portrait
+        // and landscape mode.
+        if (mCountryMode && mLocaleOptions.size() < MIN_REGIONS_FOR_SUGGESTIONS) {
             return false;
         }
         return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b0ef012..bbefcb5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4012,6 +4012,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
                     + Integer.toHexString(mHistoryCur.states2));
             addHistoryRecordLocked(elapsedRealtime, uptime);
+            mBluetoothScanTimer.startRunningLocked(elapsedRealtime);
         }
         mBluetoothScanNesting++;
         getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime);
@@ -4034,6 +4035,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: "
                     + Integer.toHexString(mHistoryCur.states2));
             addHistoryRecordLocked(elapsedRealtime, uptime);
+            mBluetoothScanTimer.stopRunningLocked(elapsedRealtime);
         }
         getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime);
     }
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 14ebe22..79138b7 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -85,6 +85,7 @@
     public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
     public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
     public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
+    public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels";
     public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
 
     public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
@@ -287,9 +288,15 @@
         };
 
         for (int i = 0; i < configResIds.length; i++) {
+            String key = configResIdKeys[i];
+            // if we already have some of these parameters in power_profile.xml, ignore the
+            // value in config.xml
+            if ((sPowerMap.containsKey(key) && (Double) sPowerMap.get(key) > 0)) {
+                continue;
+            }
             int value = resources.getInteger(configResIds[i]);
             if (value > 0) {
-                sPowerMap.put(configResIdKeys[i], (double) value);
+                sPowerMap.put(key, (double) value);
             }
         }
     }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 794a6d6..0f257d7 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -24,6 +24,7 @@
 import android.app.SearchManager;
 import android.os.UserHandle;
 
+import android.text.TextUtils;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.IRotationWatcher.Stub;
@@ -514,6 +515,11 @@
             mDecorContentParent.setWindowTitle(title);
         }
         mTitle = title;
+        WindowManager.LayoutParams params = getAttributes();
+        if (!TextUtils.equals(title, params.getTitle())) {
+            params.setTitle(title);
+            dispatchWindowAttributesChanged(getAttributes());
+        }
     }
 
     @Override
@@ -680,7 +686,7 @@
     }
 
     @Override
-    public void onMultiWindowChanged() {
+    public void onMultiWindowModeChanged() {
         if (mDecor != null) {
             mDecor.onConfigurationChanged(getContext().getResources().getConfiguration());
         }
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index ee73b90..bed5a2e 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -238,6 +238,14 @@
         return total;
     }
 
+    public static int[] convertToIntArray(List<Integer> list) {
+        int[] array = new int[list.size()];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
+
     /**
      * Adds value to given array if not already present, providing set-like
      * behavior.
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index bd0e6ce..d8be9fd 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -402,7 +402,7 @@
 
         // Initialize destination fields
         mDstMessenger = dstMessenger;
-
+        linkToDeathMonitor();
         if (DBG) log("connected srcHandler to the dstMessenger X");
     }
 
@@ -844,22 +844,30 @@
         msg.arg1 = status;
         msg.obj = this;
         msg.replyTo = mDstMessenger;
+        if (!linkToDeathMonitor()) {
+            // Override status to indicate failure
+            msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+        }
 
-        /*
-         * Link to death only when bindService isn't used.
-         */
-        if (mConnection == null) {
+        mSrcHandler.sendMessage(msg);
+    }
+
+    /**
+     * Link to death monitor for destination messenger. Returns true if successfully binded to
+     * destination messenger; false otherwise.
+     */
+    private boolean linkToDeathMonitor() {
+        // Link to death only when bindService isn't used and not already linked.
+        if (mConnection == null && mDeathMonitor == null) {
             mDeathMonitor = new DeathMonitor();
             try {
                 mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
             } catch (RemoteException e) {
                 mDeathMonitor = null;
-                // Override status to indicate failure
-                msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
+                return false;
             }
         }
-
-        mSrcHandler.sendMessage(msg);
+        return true;
     }
 
     /**
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index c46851e..1ead5b3 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -56,7 +56,7 @@
      * @return the string reference that was validated
      * @throws IllegalArgumentException if {@code string} is empty
      */
-    public static @NonNull String checkStringNotEmpty(final String string) {
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
         if (TextUtils.isEmpty(string)) {
             throw new IllegalArgumentException();
         }
@@ -73,7 +73,7 @@
      * @return the string reference that was validated
      * @throws IllegalArgumentException if {@code string} is empty
      */
-    public static @NonNull String checkStringNotEmpty(final String string,
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
             final Object errorMessage) {
         if (TextUtils.isEmpty(string)) {
             throw new IllegalArgumentException(String.valueOf(errorMessage));
@@ -141,13 +141,17 @@
     /**
      * Check the requested flags, throwing if any requested flags are outside
      * the allowed set.
+     *
+     * @return the validated requested flags.
      */
-    public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
+    public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
         if ((requestedFlags & allowedFlags) != requestedFlags) {
             throw new IllegalArgumentException("Requested flags 0x"
                     + Integer.toHexString(requestedFlags) + ", but only 0x"
                     + Integer.toHexString(allowedFlags) + " are allowed");
         }
+
+        return requestedFlags;
     }
 
     /**
@@ -170,6 +174,37 @@
     /**
      * Ensures that that the argument numeric value is non-negative.
      *
+     * @param value a numeric int value
+     *
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
+        if (value < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric long value
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static long checkArgumentNonnegative(final long value) {
+        if (value < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
      * @param value a numeric long value
      * @param errorMessage the exception message to use if the check fails
      * @return the validated numeric value
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 6c1ebb4..3a4afad 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -27,13 +27,12 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-
-import java.lang.ref.WeakReference;
+import android.view.inputmethod.InputConnectionInspector;
+import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 
 public abstract class IInputConnectionWrapper extends IInputContext.Stub {
     static final String TAG = "IInputConnectionWrapper";
@@ -61,7 +60,7 @@
     private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
     private static final int DO_CLEAR_META_KEY_STATES = 130;
     private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
-    private static final int DO_REPORT_FINISH = 150;
+    private static final int DO_CLOSE_CONNECTION = 150;
 
     @GuardedBy("mLock")
     @Nullable
@@ -222,8 +221,8 @@
                 seq, callback));
     }
 
-    public void reportFinish() {
-        dispatchMessage(obtainMessage(DO_REPORT_FINISH));
+    public void closeConnection() {
+        dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
     }
 
     void dispatchMessage(Message msg) {
@@ -501,10 +500,10 @@
                 }
                 return;
             }
-            case DO_REPORT_FINISH: {
+            case DO_CLOSE_CONNECTION: {
                 // Note that we do not need to worry about race condition here, because 1) mFinished
                 // is updated only inside this block, and 2) the code here is running on a Handler
-                // hence we assume multiple DO_REPORT_FINISH messages will not be handled at the
+                // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
                 // same time.
                 if (isFinished()) {
                     return;
@@ -518,11 +517,10 @@
                     if (ic == null) {
                         return;
                     }
-                    ic.finishComposingText();
-                    // TODO: Make reportFinish() public method of InputConnection to remove this
-                    // check.
-                    if (ic instanceof BaseInputConnection) {
-                        ((BaseInputConnection) ic).reportFinish();
+                    @MissingMethodFlags
+                    final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
+                    if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+                        ic.closeConnection();
                     }
                 } finally {
                     synchronized (mLock) {
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 85b8606..f9884d8 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -487,6 +487,10 @@
         return null;
     }
 
+    public void closeConnection() {
+        // Nothing should happen when called from input method.
+    }
+
     private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
         return (mMissingMethods & methodFlag) == methodFlag;
     }
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index 526e2ae..9e2cbdb 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -45,7 +45,8 @@
     private static float[] createLUT(TimeInterpolator interpolator, long duration) {
         long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
         int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
-        int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs);
+        // We need 2 frame values as the minimal.
+        int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
         float values[] = new float[numAnimFrames];
         float lastFrame = numAnimFrames - 1;
         for (int i = 0; i < numAnimFrames; i++) {
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index 409a17f..e59d7ba 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -136,7 +136,7 @@
     public void setPhoneWindow(PhoneWindow owner, boolean show) {
         mOwner = owner;
         mShow = show;
-        mOverlayWithAppContent = owner.getOverlayDecorCaption();
+        mOverlayWithAppContent = owner.isOverlayWithDecorCaptionEnabled();
         if (mOverlayWithAppContent) {
             // The caption is covering the content, so we make its background transparent to make
             // the content visible.
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index a96b5a0..7f7528d 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -83,13 +83,9 @@
         return false;
     }
 
-    /**
-     * @hide
-     */
     @Override
-    public void reportFinish() {
-        super.reportFinish();
-
+    public void closeConnection() {
+        super.closeConnection();
         synchronized(this) {
             while (mBatchEditNesting > 0) {
                 endBatchEdit();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9d14478..3d892af 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1099,7 +1099,8 @@
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
+                || mode == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
         return passwordEnabled && savedPasswordExists(userId);
     }
 
diff --git a/services/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
similarity index 94%
rename from services/core/java/com/android/server/SystemConfig.java
rename to core/java/com/android/server/SystemConfig.java
index 30e0ceb..07912cd 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
 import static com.android.internal.util.ArrayUtils.appendInt;
 
 import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
 import android.os.Environment;
@@ -115,6 +116,9 @@
     // These are the packages that should not run under system user
     final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
 
+    // These are the components that are enabled by default as VR mode listener services.
+    final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
+
     public static SystemConfig getInstance() {
         synchronized (SystemConfig.class) {
             if (sInstance == null) {
@@ -168,6 +172,10 @@
         return mSystemUserBlacklistedApps;
     }
 
+    public ArraySet<ComponentName> getDefaultVrComponents() {
+        return mDefaultVrComponents;
+    }
+
     SystemConfig() {
         // Read configuration from system
         readPermissions(Environment.buildPath(
@@ -431,6 +439,19 @@
                         mSystemUserBlacklistedApps.add(pkgname);
                     }
                     XmlUtils.skipCurrentTag(parser);
+                } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    String clsname = parser.getAttributeValue(null, "class");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else if (clsname == null) {
+                        Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
+                    }
+                    XmlUtils.skipCurrentTag(parser);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                     continue;
diff --git a/core/java/com/android/server/backup/ShortcutBackupHelper.java b/core/java/com/android/server/backup/ShortcutBackupHelper.java
new file mode 100644
index 0000000..0b3f2ae
--- /dev/null
+++ b/core/java/com/android/server/backup/ShortcutBackupHelper.java
@@ -0,0 +1,70 @@
+/*
+ * 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.backup;
+
+import android.app.backup.BlobBackupHelper;
+import android.content.Context;
+import android.content.pm.IShortcutService;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+public class ShortcutBackupHelper extends BlobBackupHelper {
+    private static final String TAG = "ShortcutBackupAgent";
+    private static final int BLOB_VERSION = 1;
+
+    private static final String KEY_USER_FILE = "shortcutuser.xml";
+
+    public ShortcutBackupHelper() {
+        super(BLOB_VERSION, KEY_USER_FILE);
+    }
+
+    private IShortcutService getShortcutService() {
+        return IShortcutService.Stub.asInterface(
+                ServiceManager.getService(Context.SHORTCUT_SERVICE));
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        switch (key) {
+            case KEY_USER_FILE:
+                try {
+                    return getShortcutService().getBackupPayload(UserHandle.USER_SYSTEM);
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Backup failed", e);
+                }
+                break;
+            default:
+                Slog.w(TAG, "Unknown key: " + key);
+        }
+        return null;
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        switch (key) {
+            case KEY_USER_FILE:
+                try {
+                    getShortcutService().applyRestore(payload, UserHandle.USER_SYSTEM);
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Restore failed", e);
+                }
+                break;
+            default:
+                Slog.w(TAG, "Unknown key: " + key);
+        }
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 181ed51..2d12fcd 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -17,9 +17,9 @@
 package com.android.server.backup;
 
 import android.app.IWallpaperManager;
+import android.app.backup.BackupAgentHelper;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupAgentHelper;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.WallpaperBackupHelper;
@@ -48,6 +48,7 @@
     private static final String NOTIFICATION_HELPER = "notifications";
     private static final String PERMISSION_HELPER = "permissions";
     private static final String USAGE_STATS_HELPER = "usage_stats";
+    private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
 
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
@@ -100,6 +101,7 @@
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
         super.onBackup(oldState, data, newState);
     }
 
@@ -138,6 +140,7 @@
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
+        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
 
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c6112d9..8a512a6 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -103,7 +103,6 @@
     android_util_jar_StrictJarFile.cpp \
     android_graphics_Canvas.cpp \
     android_graphics_Picture.cpp \
-    android/graphics/AvoidXfermode.cpp \
     android/graphics/Bitmap.cpp \
     android/graphics/BitmapFactory.cpp \
     android/graphics/Camera.cpp \
diff --git a/core/jni/android/graphics/AvoidXfermode.cpp b/core/jni/android/graphics/AvoidXfermode.cpp
deleted file mode 100644
index 9ca1f26..0000000
--- a/core/jni/android/graphics/AvoidXfermode.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "AvoidXfermode.h"
-#include "SkColorPriv.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkString.h"
-
-AvoidXfermode::AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
-    if (tolerance > 255) {
-        tolerance = 255;
-    }
-    fTolerance = SkToU8(tolerance);
-    fOpColor = opColor;
-    fDistMul = (256 << 14) / (tolerance + 1);
-    fMode = mode;
-}
-
-SkFlattenable* AvoidXfermode::CreateProc(SkReadBuffer& buffer) {
-    const SkColor color = buffer.readColor();
-    const unsigned tolerance = buffer.readUInt();
-    const unsigned mode = buffer.readUInt();
-    return Create(color, tolerance, (Mode)mode);
-}
-
-void AvoidXfermode::flatten(SkWriteBuffer& buffer) const {
-    buffer.writeColor(fOpColor);
-    buffer.writeUInt(fTolerance);
-    buffer.writeUInt(fMode);
-}
-
-// returns 0..31
-static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
-    SkASSERT(r <= SK_R16_MASK);
-    SkASSERT(g <= SK_G16_MASK);
-    SkASSERT(b <= SK_B16_MASK);
-
-    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
-    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
-    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
-
-    return SkMax32(dr, SkMax32(dg, db));
-}
-
-// returns 0..255
-static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
-    SkASSERT(r <= 0xFF);
-    SkASSERT(g <= 0xFF);
-    SkASSERT(b <= 0xFF);
-
-    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
-    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
-    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
-
-    return SkMax32(dr, SkMax32(dg, db));
-}
-
-static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
-    int tmp = dist * mul - sub;
-    int result = (tmp + (1 << 13)) >> 14;
-
-    return result;
-}
-
-static inline unsigned Accurate255To256(unsigned x) {
-    return x + (x >> 7);
-}
-
-void AvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
-                             const SkAlpha aa[]) const {
-    unsigned    opR = SkColorGetR(fOpColor);
-    unsigned    opG = SkColorGetG(fOpColor);
-    unsigned    opB = SkColorGetB(fOpColor);
-    uint32_t    mul = fDistMul;
-    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
-
-    int MAX, mask;
-
-    if (kTargetColor_Mode == fMode) {
-        mask = -1;
-        MAX = 255;
-    } else {
-        mask = 0;
-        MAX = 0;
-    }
-
-    for (int i = 0; i < count; i++) {
-        int d = color_dist32(dst[i], opR, opG, opB);
-        // now reverse d if we need to
-        d = MAX + (d ^ mask) - mask;
-        SkASSERT((unsigned)d <= 255);
-        d = Accurate255To256(d);
-
-        d = scale_dist_14(d, mul, sub);
-        SkASSERT(d <= 256);
-
-        if (d > 0) {
-            if (aa) {
-                d = SkAlphaMul(d, Accurate255To256(*aa++));
-                if (0 == d) {
-                    continue;
-                }
-            }
-            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
-        }
-    }
-}
-
-static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
-    SkASSERT(scale <= 32);
-    scale <<= 3;
-
-    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
-                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
-                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
-}
-
-void AvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
-                             const SkAlpha aa[]) const {
-    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
-    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
-    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
-    uint32_t    mul = fDistMul;
-    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
-
-    int MAX, mask;
-
-    if (kTargetColor_Mode == fMode) {
-        mask = -1;
-        MAX = 31;
-    } else {
-        mask = 0;
-        MAX = 0;
-    }
-
-    for (int i = 0; i < count; i++) {
-        int d = color_dist16(dst[i], opR, opG, opB);
-        // now reverse d if we need to
-        d = MAX + (d ^ mask) - mask;
-        SkASSERT((unsigned)d <= 31);
-        // convert from 0..31 to 0..32
-        d += d >> 4;
-        d = scale_dist_14(d, mul, sub);
-        SkASSERT(d <= 32);
-
-        if (d > 0) {
-            if (aa) {
-                d = SkAlphaMul(d, Accurate255To256(*aa++));
-                if (0 == d) {
-                    continue;
-                }
-            }
-            dst[i] = SkBlend3216(src[i], dst[i], d);
-        }
-    }
-}
-
-void AvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
-        const SkAlpha aa[]) const {
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void AvoidXfermode::toString(SkString* str) const {
-    str->append("AvoidXfermode: opColor: ");
-    str->appendHex(fOpColor);
-    str->appendf("distMul: %d ", fDistMul);
-
-    static const char* gModeStrings[] = { "Avoid", "Target" };
-
-    str->appendf("mode: %s", gModeStrings[fMode]);
-}
-#endif
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
deleted file mode 100644
index 8b7fb71..0000000
--- a/core/jni/android/graphics/AvoidXfermode.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef AvoidXfermode_DEFINED
-#define AvoidXfermode_DEFINED
-
-#include "SkColor.h"
-#include "SkTypes.h"
-#include "SkXfermode.h"
-
-/** \class AvoidXfermode
-
-    This xfermode will draw the src everywhere except on top of the specified
-    color.
-*/
-class AvoidXfermode : public SkXfermode {
-public:
-    enum Mode {
-        kAvoidColor_Mode,   //!< draw everywhere except on the opColor
-        kTargetColor_Mode   //!< draw only on top of the opColor
-    };
-
-    /** This xfermode draws, or doesn't draw, based on the destination's
-        distance from an op-color.
-
-        There are two modes, and each mode interprets a tolerance value.
-
-        Avoid: In this mode, drawing is allowed only on destination pixels that
-               are different from the op-color.
-               Tolerance near 0: avoid any colors even remotely similar to the op-color
-               Tolerance near 255: avoid only colors nearly identical to the op-color
-
-        Target: In this mode, drawing only occurs on destination pixels that
-                are similar to the op-color
-                Tolerance near 0: draw only on colors that are nearly identical to the op-color
-                Tolerance near 255: draw on any colors even remotely similar to the op-color
-     */
-    static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
-        return new AvoidXfermode(opColor, tolerance, mode);
-    }
-
-    // overrides from SkXfermode
-    void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
-            const SkAlpha aa[]) const override;
-    void xfer16(uint16_t dst[], const SkPMColor src[], int count,
-            const SkAlpha aa[]) const override;
-    void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
-            const SkAlpha aa[]) const override;
-
-    SK_TO_STRING_OVERRIDE()
-    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(AvoidXfermode)
-
-protected:
-    AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
-    void flatten(SkWriteBuffer&) const override;
-
-private:
-    SkColor     fOpColor;
-    uint32_t    fDistMul;   // x.14 cached from fTolerance
-    uint8_t     fTolerance;
-    Mode        fMode;
-
-    typedef SkXfermode INHERITED;
-};
-
-#endif
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 27b9830..22a81d4 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -251,13 +251,6 @@
 
 void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
         SkColorTable* ctable) {
-    {
-        android::AutoMutex _lock(mLock);
-        if (mPinnedRefCount) {
-            ALOGW("Called reconfigure on a bitmap that is in use! This may"
-                    " cause graphical corruption!");
-        }
-    }
     mPixelRef->reconfigure(info, rowBytes, ctable);
 }
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 27d8fed..1844a98 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -823,7 +823,7 @@
     static jfloat doRunAdvance(const Paint* paint, Typeface* typeface, const jchar buf[],
             jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
-        if (offset == count) {
+        if (offset == start + count) {
             return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
                     bufSize, nullptr);
         }
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index a2662f9..b04293e 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include "jni.h"
 #include "GraphicsJNI.h"
+#include "jni.h"
 #include "core_jni_helpers.h"
-#include "log/log.h"
 
+#include "PathParser.h"
 #include "VectorDrawable.h"
 
 #include <hwui/Paint.h>
@@ -27,43 +27,15 @@
 using namespace uirenderer;
 using namespace uirenderer::VectorDrawable;
 
+/**
+ * VectorDrawable's pre-draw construction.
+ */
 static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
     VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
     return reinterpret_cast<jlong>(tree);
 }
 
-static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
-        jfloat viewportWidth, jfloat viewportHeight) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    tree->setViewportSize(viewportWidth, viewportHeight);
-}
-
-static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    return tree->setRootAlpha(alpha);
-}
-
-static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    return tree->getRootAlpha();
-}
-
-static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    tree->setAllowCaching(allowCaching);
-}
-
-static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
-        jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
-    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
-    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    SkRect rect;
-    GraphicsJNI::jrect_to_rect(env, jrect, &rect);
-    SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
-    tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
-}
-
 static jlong createEmptyFullPath(JNIEnv*, jobject) {
     VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
     return reinterpret_cast<jlong>(newPath);
@@ -76,46 +48,6 @@
     return reinterpret_cast<jlong>(newPath);
 }
 
-static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
-        jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
-        jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
-        jint strokeLineCap, jint strokeLineJoin, jint fillType) {
-    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
-            trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
-            strokeLineJoin, fillType);
-}
-
-static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
-    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
-    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
-    path->setFillGradient(fillShader);
-}
-
-static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
-    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
-    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
-    path->setStrokeGradient(strokeShader);
-}
-
-static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
-        jbyteArray outProperties, jint length) {
-    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    int8_t pathProperties[length];
-    bool success = fullPath->getProperties(pathProperties, length);
-    env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
-    return success;
-}
-
-static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
-        jfloatArray outProperties, jint length) {
-    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    float groupProperties[length];
-    bool success = group->getProperties(groupProperties, length);
-    env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
-    return success;
-}
-
 static jlong createEmptyClipPath(JNIEnv*, jobject) {
     VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
     return reinterpret_cast<jlong>(newPath);
@@ -146,180 +78,265 @@
     env->ReleaseStringUTFChars(nameStr, nodeName);
 }
 
-static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
-        jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
-    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->updateLocalMatrix(rotate, pivotX, pivotY, scaleX, scaleY, translateX, translateY);
-}
-
 static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
     VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
     group->addChild(child);
 }
 
+static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    tree->setAllowCaching(allowCaching);
+}
+
+/**
+ * Draw
+ */
+static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
+        jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    SkRect rect;
+    GraphicsJNI::jrect_to_rect(env, jrect, &rect);
+    SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+    tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+}
+
+/**
+ * Setters and getters for updating staging properties that can happen both pre-draw and post draw.
+ */
+static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
+        jfloat viewportWidth, jfloat viewportHeight) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    tree->mutateStagingProperties()->setViewportSize(viewportWidth, viewportHeight);
+}
+
+static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    return tree->mutateStagingProperties()->setRootAlpha(alpha);
+}
+
+static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    return tree->stagingProperties()->getRootAlpha();
+}
+
+static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
+        jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
+        jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
+        jint strokeLineCap, jint strokeLineJoin, jint fillType) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->mutateStagingProperties()->updateProperties(strokeWidth, strokeColor, strokeAlpha,
+            fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit,
+            strokeLineCap, strokeLineJoin, fillType);
+}
+
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+    path->mutateStagingProperties()->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+    path->mutateStagingProperties()->setStrokeGradient(strokeShader);
+}
+
+static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
+        jbyteArray outProperties, jint length) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    int8_t pathProperties[length];
+    bool success = fullPath->stagingProperties()->copyProperties(pathProperties, length);
+    env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
+    return success;
+}
+
+static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
+        jfloatArray outProperties, jint length) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    float groupProperties[length];
+    bool success = group->stagingProperties()->copyProperties(groupProperties, length);
+    env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
+    return success;
+}
+
+static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
+        jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->mutateStagingProperties()->updateProperties(rotate, pivotX, pivotY, scaleX, scaleY,
+            translateX, translateY);
+}
+
 static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
         jint stringLength) {
     VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
     const char* pathString = env->GetStringUTFChars(inputStr, NULL);
-    path->setPath(pathString, stringLength);
+
+    PathParser::ParseResult result;
+    PathData data;
+    PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+    path->mutateStagingProperties()->setData(data);
     env->ReleaseStringUTFChars(inputStr, pathString);
 }
 
+/**
+ * Setters and getters that should only be called from animation thread for animation purpose.
+ */
 static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getRotation();
+    return group->stagingProperties()->getRotation();
 }
 
 static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setRotation(rotation);
+    group->mutateStagingProperties()->setRotation(rotation);
 }
 
 static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getPivotX();
+    return group->stagingProperties()->getPivotX();
 }
 
 static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setPivotX(pivotX);
+    group->mutateStagingProperties()->setPivotX(pivotX);
 }
 
 static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getPivotY();
+    return group->stagingProperties()->getPivotY();
 }
 
 static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setPivotY(pivotY);
+    group->mutateStagingProperties()->setPivotY(pivotY);
 }
 
 static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getScaleX();
+    return group->stagingProperties()->getScaleX();
 }
 
 static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setScaleX(scaleX);
+    group->mutateStagingProperties()->setScaleX(scaleX);
 }
 
 static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getScaleY();
+    return group->stagingProperties()->getScaleY();
 }
 
 static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setScaleY(scaleY);
+    group->mutateStagingProperties()->setScaleY(scaleY);
 }
 
 static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getTranslateX();
+    return group->stagingProperties()->getTranslateX();
 }
 
 static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setTranslateX(translateX);
+    group->mutateStagingProperties()->setTranslateX(translateX);
 }
 
 static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    return group->getTranslateY();
+    return group->stagingProperties()->getTranslateY();
 }
 
 static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
-    group->setTranslateY(translateY);
+    group->mutateStagingProperties()->setTranslateY(translateY);
 }
 
 static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
     VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
     PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
-    path->setPathData(*pathData);
+    path->mutateStagingProperties()->setData(*pathData);
 }
 
 static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getStrokeWidth();
+    return fullPath->stagingProperties()->getStrokeWidth();
 }
 
 static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setStrokeWidth(strokeWidth);
+    fullPath->mutateStagingProperties()->setStrokeWidth(strokeWidth);
 }
 
 static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getStrokeColor();
+    return fullPath->stagingProperties()->getStrokeColor();
 }
 
 static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setStrokeColor(strokeColor);
+    fullPath->mutateStagingProperties()->setStrokeColor(strokeColor);
 }
 
 static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getStrokeAlpha();
+    return fullPath->stagingProperties()->getStrokeAlpha();
 }
 
 static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setStrokeAlpha(strokeAlpha);
+    fullPath->mutateStagingProperties()->setStrokeAlpha(strokeAlpha);
 }
 
 static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getFillColor();
+    return fullPath->stagingProperties()->getFillColor();
 }
 
 static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setFillColor(fillColor);
+    fullPath->mutateStagingProperties()->setFillColor(fillColor);
 }
 
 static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getFillAlpha();
+    return fullPath->stagingProperties()->getFillAlpha();
 }
 
 static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setFillAlpha(fillAlpha);
+    fullPath->mutateStagingProperties()->setFillAlpha(fillAlpha);
 }
 
 static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getTrimPathStart();
+    return fullPath->stagingProperties()->getTrimPathStart();
 }
 
 static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setTrimPathStart(trimPathStart);
+    fullPath->mutateStagingProperties()->setTrimPathStart(trimPathStart);
 }
 
 static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getTrimPathEnd();
+    return fullPath->stagingProperties()->getTrimPathEnd();
 }
 
 static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setTrimPathEnd(trimPathEnd);
+    fullPath->mutateStagingProperties()->setTrimPathEnd(trimPathEnd);
 }
 
 static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    return fullPath->getTrimPathOffset();
+    return fullPath->stagingProperties()->getTrimPathOffset();
 }
 
 static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
     VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
-    fullPath->setTrimPathOffset(trimPathOffset);
+    fullPath->mutateStagingProperties()->setTrimPathOffset(trimPathOffset);
 }
 
 static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 8724729..42dc983 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -16,23 +16,39 @@
 
 #include "context_hub.h"
 
+#define LOG_NDEBUG 0
+#define LOG_TAG "ContextHubService"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <map>
+#include <queue>
 #include <string.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 
-#include <jni.h>
+#include <cutils/log.h>
+
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
-#include "stdint.h"
-#include "stdlib.h"
+
+//static constexpr int OS_APP_ID=-1;
+
+static constexpr int MIN_APP_ID=1;
+static constexpr int MAX_APP_ID=128;
+
+static constexpr size_t MSG_HEADER_SIZE=4;
+static constexpr int HEADER_FIELD_MSG_TYPE=0;
+//static constexpr int HEADER_FIELD_MSG_VERSION=1;
+static constexpr int HEADER_FIELD_HUB_HANDLE=2;
+static constexpr int HEADER_FIELD_APP_INSTANCE=3;
 
 
 namespace android {
 
 namespace {
 
-// TODO: We should share this array_length function widely around Android
-//     code.
 /*
  * Finds the length of a statically-sized array using template trickery that
  * also prevents it from being applied to the wrong type.
@@ -64,35 +80,207 @@
     jmethodID contextHubInfoSetPeakPowerDrawMw;
     jmethodID contextHubInfoSetSupportedSensors;
     jmethodID contextHubInfoSetMemoryRegions;
+    jmethodID contextHubInfoSetMaxPacketLenBytes;
 
     jmethodID contextHubServiceMsgReceiptCallback;
+    jmethodID contextHubServiceAddAppInstance;
 };
 
 struct context_hub_info_s {
-    int cookie;
+    uint32_t *cookies;
     int numHubs;
     const struct context_hub_t *hubs;
     struct context_hub_module_t *contextHubModule;
 };
 
+struct app_instance_info_s {
+    uint32_t hubHandle; // Id of the hub this app is on
+    int instanceId; // systemwide unique instance id - assigned
+    struct hub_app_info appInfo; // returned from the HAL
+    uint64_t truncName; // Possibly truncated name - logging
+};
+
 struct contextHubServiceDb_s {
     int initialized;
     context_hub_info_s hubInfo;
     jniInfo_s jniInfo;
+    std::queue<int> freeIds;
+    std::map<int, app_instance_info_s *> appInstances;
 };
 
 }  // unnamed namespace
 
 static contextHubServiceDb_s db;
 
-int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
+int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
                          void *cookie);
 
+const context_hub_t *get_hub_info(int hubHandle) {
+    if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
+        return &db.hubInfo.hubs[hubHandle];
+    }
+    return nullptr;
+}
+
+static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
+    const context_hub_t *info = get_hub_info(hubHandle);
+
+    if (info) {
+        return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
+    } else {
+        ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+        return -1;
+    }
+}
+
+static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
+    const context_hub_t *info = get_hub_info(hubHandle);
+
+    if (info) {
+        msg->app = info->os_app_name;
+        return 0;
+    } else {
+        ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
+        return -1;
+    }
+}
+
+static int get_hub_id_for_app_instance(int id) {
+    if (db.appInstances.find(id) == db.appInstances.end()) {
+        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+        return -1;
+    }
+
+    int hubHandle = db.appInstances[id]->hubHandle;
+
+    return db.hubInfo.hubs[hubHandle].hub_id;
+}
+
+static int set_dest_app(hub_message_t *msg, int id) {
+    if (db.appInstances.find(id) == db.appInstances.end()) {
+        ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id);
+        return -1;
+    }
+
+    msg->app = db.appInstances[id]->appInfo.name;
+    return 0;
+}
+
+static void send_query_for_apps() {
+    hub_message_t msg;
+
+    msg.message_type = CONTEXT_HUB_QUERY_APPS;
+    msg.message_len  = 0;
+
+    for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
+        ALOGD("Sending query for apps to hub %d", i);
+        set_os_app_as_destination(&msg, i);
+        if (send_msg_to_hub(&msg, i) != 0) {
+          ALOGW("Could not query hub %i for apps", i);
+        }
+    }
+}
+
+static int return_id(int id) {
+    // Note : This method is not thread safe.
+    // id returned is guarenteed to be in use
+    db.freeIds.push(id);
+    return 0;
+}
+
+static int generate_id(void) {
+    // Note : This method is not thread safe.
+    int retVal = -1;
+
+    if (!db.freeIds.empty()) {
+        retVal = db.freeIds.front();
+        db.freeIds.pop();
+    }
+
+    return retVal;
+}
+
+int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
+    // Not checking if the apps are indeed distinct
+
+    app_instance_info_s *entry;
+    void *appName;
+    hub_app_name_t *name;
+
+    assert(appInfo && appInfo->name && appInfo->name->app_name);
+
+    entry = (app_instance_info_s *) malloc(sizeof(app_instance_info_s));
+    appName = malloc(appInfo->name->app_name_len);
+    name = (hub_app_name_t *) malloc(sizeof(hub_app_name_t));
+
+    int appInstanceHandle = generate_id();
+
+    if (appInstanceHandle < 0 || !appName || !entry || !name) {
+        ALOGE("Cannot find resources to add app instance %d, %p, %p",
+            appInstanceHandle, appName, entry);
+
+        free(appName);
+        free(entry);
+        free(name);
+
+        if (appInstanceHandle >= 0) {
+            return_id(appInstanceHandle);
+        }
+
+        return -1;
+    }
+
+    memcpy(&(entry->appInfo), appInfo, sizeof(entry->appInfo));
+    memcpy(appName, appInfo->name->app_name, appInfo->name->app_name_len);
+    name->app_name = appName;
+    name->app_name_len = appInfo->name->app_name_len;
+    entry->appInfo.name = name;
+    entry->truncName = 0;
+    memcpy(&(entry->truncName), name->app_name,
+           sizeof(entry->truncName) < name->app_name_len ?
+           sizeof(entry->truncName) : name->app_name_len);
+
+    // Not checking for sanity of hubId
+    entry->hubHandle = hubHandle;
+    entry->instanceId = appInstanceHandle;
+    db.appInstances[appInstanceHandle] = entry;
+
+    // Finally - let the service know of this app instance
+    env->CallIntMethod(db.jniInfo.jContextHubService,
+                       db.jniInfo.contextHubServiceAddAppInstance,
+                       hubHandle, entry->instanceId, entry->truncName,
+                       entry->appInfo.version);
+
+    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
+          " as appInstance %d, original name_length %" PRId32, entry->truncName,
+          entry->hubHandle, appInstanceHandle, name->app_name_len);
+
+    return appInstanceHandle;
+}
+
+int delete_app_instance(int id) {
+    if (db.appInstances.find(id) == db.appInstances.end()) {
+        return -1;
+    }
+
+    return_id(id);
+
+    if (db.appInstances[id]) {
+        // Losing the const cast below. This is intentional.
+        free((void *)db.appInstances[id]->appInfo.name->app_name);
+        free((void *)db.appInstances[id]->appInfo.name);
+        free(db.appInstances[id]);
+        db.appInstances.erase(id);
+    }
+
+    return 0;
+}
+
+
 static void initContextHubService() {
     int err = 0;
-    db.hubInfo.hubs = NULL;
+    db.hubInfo.hubs = nullptr;
     db.hubInfo.numHubs = 0;
-    db.hubInfo.cookie = 0;
     int i;
 
     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
@@ -103,26 +291,45 @@
             strerror(-err));
     }
 
-    if (db.hubInfo.contextHubModule) {
-      ALOGD("Fetching hub info");
-      db.hubInfo.numHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
-                                                                 &db.hubInfo.hubs);
+    // Prep for storing app info
+    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+        db.freeIds.push(i);
+    }
 
-      if (db.hubInfo.numHubs > 0) {
-        for (i = 0; i < db.hubInfo.numHubs; i++) {
-          // TODO : Event though one cookie is OK for now, lets change
-          // this to be one per hub
-          db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
-                                                          context_hub_callback,
-                                                          &db.hubInfo.cookie);
+    if (db.hubInfo.contextHubModule) {
+        int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
+                                                                 &db.hubInfo.hubs);
+        ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
+        db.hubInfo.numHubs = retNumHubs;
+
+        if (db.hubInfo.numHubs > 0) {
+            db.hubInfo.numHubs = retNumHubs;
+            db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
+
+            if (!db.hubInfo.cookies) {
+                ALOGW("Ran out of memory allocating cookies, bailing");
+                return;
+            }
+
+            for (i = 0; i < db.hubInfo.numHubs; i++) {
+                db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
+                if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
+                                                                    context_hub_callback,
+                                                                    &db.hubInfo.cookies[i]) == 0) {
+                }
+            }
         }
-      }
+
+        send_query_for_apps();
+    } else {
+        ALOGW("No Context Hub Module present");
     }
 }
 
 static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) {
     JNIEnv *env;
-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, NULL) != JNI_OK) {
+
+    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
       return -1;
     }
 
@@ -132,28 +339,131 @@
     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
     env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
 
-
-    return env->CallIntMethod(db.jniInfo.jContextHubService,
+    return (env->CallIntMethod(db.jniInfo.jContextHubService,
                           db.jniInfo.contextHubServiceMsgReceiptCallback,
-                          jheader, jmsg);
+                          jheader, jmsg) != 0);
 }
 
-int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
+int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
+    int i;
+    JNIEnv *env;
+    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+            return -1;
+    }
+
+    int numApps = msgLen/sizeof(hub_app_info);
+    hub_app_info *info = (hub_app_info *)malloc(msgLen); // handle possible alignment
+
+    if (!info) {
+        return -1;
+    }
+
+    memcpy(info, msg, msgLen);
+    for (i = 0; i < numApps; i++) {
+        add_app_instance(info, hubHandle, env);
+        info++;
+    }
+
+    free(info);
+
+    return 0;
+}
+
+
+int handle_os_message(uint32_t msgType, uint32_t hubHandle,
+                      char *msg, int msgLen) {
+    int retVal;
+
+    switch(msgType) {
+        case CONTEXT_HUB_APPS_ENABLE:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_APPS_DISABLE:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_LOAD_APP:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_UNLOAD_APP:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_QUERY_APPS:
+            retVal = handle_query_apps_response(msg, msgLen, hubHandle);
+            break;
+
+        case CONTEXT_HUB_QUERY_MEMORY:
+            retVal = 0;
+            break;
+
+        case CONTEXT_HUB_LOAD_OS:
+            retVal = 0;
+            break;
+
+        default:
+            retVal = -1;
+            break;
+
+    }
+
+    return retVal;
+}
+
+static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
+    int *ptr = (int *)cookie;
+
+    if (!ptr || *ptr >= db.hubInfo.numHubs) {
+        return false;
+    }
+
+    if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+int context_hub_callback(uint32_t hubId,
+                         const struct hub_message_t *msg,
                          void *cookie) {
-  int msgHeader[4];
+    int msgHeader[MSG_HEADER_SIZE];
 
-  msgHeader[0] = msg->message_type;
-  msgHeader[1] = 0; // TODO : HAL does not have a version field
-  msgHeader[2] = hub_id;
+    if (!msg) {
+        return -1;
+    }
 
-  onMessageReceipt(msgHeader, sizeof(msgHeader), (char *)msg->message, msg->message_len); // TODO : Populate this
-  return 0;
+    msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type;
+
+    if (!sanity_check_cookie(cookie, hubId)) {
+        ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
+              hubId, cookie);
+
+        return -1;
+    }
+
+    msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie;
+
+    if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE &&
+        msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) {
+        handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE],
+                          msgHeader[HEADER_FIELD_HUB_HANDLE],
+                          (char *)msg->message,
+                          msg->message_len);
+    } else {
+        onMessageReceipt(msgHeader, sizeof(msgHeader),
+                         (char *)msg->message, msg->message_len);
+    }
+
+    return 0;
 }
 
 static int init_jni(JNIEnv *env, jobject instance) {
 
     if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
-      return -1;
+        return -1;
     }
 
     db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
@@ -167,7 +477,6 @@
     db.jniInfo.memoryRegionsClass =
             env->FindClass("android/hardware/location/MemoryRegion");
 
-    //TODO :: Add error checking
     db.jniInfo.contextHubInfoCtor =
             env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
     db.jniInfo.contextHubInfoSetId =
@@ -209,6 +518,9 @@
     db.jniInfo.contextHubInfoSetMemoryRegions =
             env->GetMethodID(db.jniInfo.contextHubInfoClass,
                                 "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
+    db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
+             env->GetMethodID(db.jniInfo.contextHubInfoClass,
+                                "setMaxPacketLenBytes", "(I)V");
 
 
     db.jniInfo.contextHubServiceMsgReceiptCallback =
@@ -218,6 +530,11 @@
             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
             "(Ljava/lang/String;)V");
 
+    db.jniInfo.contextHubServiceAddAppInstance =
+                 env->GetMethodID(db.jniInfo.contextHubServiceClass,
+                                    "addAppInstance", "(IIJI)I");
+
+
 
     return 0;
 }
@@ -245,20 +562,29 @@
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw, hub->stopped_power_draw_mw);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw, hub->sleep_power_draw_mw);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw, hub->peak_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
+                        hub->stopped_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
+                        hub->sleep_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
+                        hub->peak_power_draw_mw);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
+                        hub->max_supported_msg_len);
+
 
     // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
-    // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, hub->connected_sensors);
+    // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
+    //                               hub->connected_sensors);
     jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
     env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
+    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
 
     // We are not getting the memory regions from the CH Hal - change this when it is available
-    jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, NULL);
+    jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
     // Note the zero size above. We do not need to set any elements
     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
 
+
     return jHub;
 }
 
@@ -267,18 +593,18 @@
     jobject hub;
     jobjectArray retArray;
 
-    initContextHubService();
-
     if (init_jni(env, instance) < 0) {
-        return NULL;
+        return nullptr;
     }
 
-    // Note : The service is clamping the number of hubs to 1
-    db.hubInfo.numHubs = 1;
-
     initContextHubService();
 
-    retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, NULL);
+    if (db.hubInfo.numHubs > 1) {
+      ALOGW("Clamping the number of hubs to 1");
+      db.hubInfo.numHubs = 1;
+    }
+
+    retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
 
     for(int i = 0; i < db.hubInfo.numHubs; i++) {
         hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
@@ -291,28 +617,27 @@
 static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
                               jbyteArray data_) {
     hub_message_t msg;
-    hub_app_name_t dest;
-    uint8_t os_name[8];
-
-    memset(os_name, 0, sizeof(os_name));
+    jint retVal = -1; // Default to failure
 
     jint *header = env->GetIntArrayElements(header_, 0);
-    //int numHeaderElements = env->GetArrayLength(header_);
+    unsigned int numHeaderElements = env->GetArrayLength(header_);
     jbyte *data = env->GetByteArrayElements(data_, 0);
     int dataBufferLength = env->GetArrayLength(data_);
 
-    /* Assume an int - thats all we understand */
-    dest.app_name_len = array_length(os_name); // TODO : Check this
-    //dest.app_name = &header[1];
-    dest.app_name = os_name;
-
-    msg.app = &dest;
-
-    msg.message_type = header[3];
-    msg.message_len = dataBufferLength;
-    msg.message = data;
-
-    jint retVal = db.hubInfo.contextHubModule->send_message(header[0], &msg);
+    if (numHeaderElements >= MSG_HEADER_SIZE) {
+        if (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0) {
+          msg.message_type = header[HEADER_FIELD_MSG_TYPE];
+          msg.message_len = dataBufferLength;
+          msg.message = data;
+          retVal = db.hubInfo.contextHubModule->send_message(
+                  get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]),
+                  &msg);
+        } else {
+          ALOGD("Could not find app instance %d", header[HEADER_FIELD_APP_INSTANCE]);
+        }
+    } else {
+        ALOGD("Malformed header len");
+    }
 
     env->ReleaseIntArrayElements(header_, header, 0);
     env->ReleaseByteArrayElements(data_, data, 0);
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 79b518f..27e2ee8 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -43,6 +43,54 @@
         ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
         : false)
 
+static JNIEnv* getenv(JavaVM* vm) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+    }
+    return env;
+}
+
+static jmethodID gOnRenderNodeDetached;
+
+class RenderNodeContext : public VirtualLightRefBase {
+public:
+    RenderNodeContext(JNIEnv* env, jobject jobjRef) {
+        env->GetJavaVM(&mVm);
+        // This holds a weak ref because otherwise there's a cyclic global ref
+        // with this holding a strong global ref to the view which holds
+        // a strong ref to RenderNode which holds a strong ref to this.
+        mWeakRef = env->NewWeakGlobalRef(jobjRef);
+    }
+
+    virtual ~RenderNodeContext() {
+        JNIEnv* env = getenv(mVm);
+        env->DeleteWeakGlobalRef(mWeakRef);
+    }
+
+    jobject acquireLocalRef(JNIEnv* env) {
+        return env->NewLocalRef(mWeakRef);
+    }
+
+private:
+    JavaVM* mVm;
+    jweak mWeakRef;
+};
+
+// Called by ThreadedRenderer's JNI layer
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node) {
+    auto context = reinterpret_cast<RenderNodeContext*>(node->getUserContext());
+    if (!context) return;
+    jobject jnode = context->acquireLocalRef(env);
+    if (!jnode) {
+        // The owning node has been GC'd, release the context
+        node->setUserContext(nullptr);
+        return;
+    }
+    env->CallVoidMethod(jnode, gOnRenderNodeDetached);
+    env->DeleteLocalRef(jnode);
+}
+
 // ----------------------------------------------------------------------------
 // DisplayList view properties
 // ----------------------------------------------------------------------------
@@ -59,7 +107,8 @@
     return renderNode->getDebugSize();
 }
 
-static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) {
+static jlong android_view_RenderNode_create(JNIEnv* env, jobject thiz,
+        jstring name) {
     RenderNode* renderNode = new RenderNode();
     renderNode->incStrong(0);
     if (name != NULL) {
@@ -67,6 +116,7 @@
         renderNode->setName(textArray);
         env->ReleaseStringUTFChars(name, textArray);
     }
+    renderNode->setUserContext(new RenderNodeContext(env, thiz));
     return reinterpret_cast<jlong>(renderNode);
 }
 
@@ -627,6 +677,9 @@
     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
             "updateWindowPositionRT", "(JIIII)V");
+    clazz = FindClassOrDie(env, "android/view/RenderNode");
+    gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
+            "onRenderNodeDetached", "()V");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 07868c5..8019326 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -120,7 +120,13 @@
     std::string mMessage;
 };
 
-class RootRenderNode : public RenderNode, ErrorHandler {
+// TODO: Clean this up, it's a bit odd to need to call over to
+// rendernode's jni layer. Probably means RootRenderNode should be pulled
+// into HWUI with appropriate callbacks for the various JNI hooks so
+// that RenderNode's JNI layer can handle its own thing
+void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
+
+class RootRenderNode : public RenderNode, ErrorHandler, TreeObserver {
 public:
     RootRenderNode(JNIEnv* env) : RenderNode() {
         mLooper = Looper::getForThread();
@@ -131,12 +137,15 @@
 
     virtual ~RootRenderNode() {}
 
-    virtual void onError(const std::string& message) {
+    virtual void onError(const std::string& message) override {
         mLooper->sendMessage(new RenderingException(mVm, message), 0);
     }
 
-    virtual void prepareTree(TreeInfo& info) {
+    virtual void prepareTree(TreeInfo& info) override {
         info.errorHandler = this;
+        if (info.mode == TreeInfo::MODE_FULL) {
+            info.observer = this;
+        }
         // TODO: This is hacky
         info.windowInsetLeft = -stagingProperties().getLeft();
         info.windowInsetTop = -stagingProperties().getTop();
@@ -145,7 +154,8 @@
         info.updateWindowPositions = false;
         info.windowInsetLeft = 0;
         info.windowInsetTop = 0;
-        info.errorHandler = NULL;
+        info.errorHandler = nullptr;
+        info.observer = nullptr;
     }
 
     void sendMessage(const sp<MessageHandler>& handler) {
@@ -171,10 +181,27 @@
         mPendingAnimatingRenderNodes.clear();
     }
 
+    virtual void onMaybeRemovedFromTree(RenderNode* node) override {
+        mMaybeRemovedNodes.insert(sp<RenderNode>(node));
+    }
+
+    void processMaybeRemovedNodes(JNIEnv* env) {
+        // We can safely access mMaybeRemovedNodes here because
+        // we will only modify it in prepareTree calls that are
+        // MODE_FULL
+
+        for (auto& node : mMaybeRemovedNodes) {
+            if (node->hasParents()) continue;
+            onRenderNodeRemoved(env, node.get());
+        }
+        mMaybeRemovedNodes.clear();
+    }
+
 private:
     sp<Looper> mLooper;
     JavaVM* mVm;
     std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
+    std::set< sp<RenderNode> > mMaybeRemovedNodes;
 };
 
 class AnimationContextBridge : public AnimationContext {
@@ -473,13 +500,16 @@
 }
 
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize, jlong rootNodePtr) {
     LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
             "Mismatched size expectations, given %d expected %d",
             frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
     env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
-    return proxy->syncAndDrawFrame();
+    int ret = proxy->syncAndDrawFrame();
+    rootRenderNode->processMaybeRemovedNodes(env);
+    return ret;
 }
 
 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -706,7 +736,7 @@
     { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
-    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSyncAndDrawFrame", "(J[JIJ)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8abb7e2..30a5993 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -845,14 +845,14 @@
     -->
     <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
         android:permissionGroup="android.permission-group.PHONE"
-        android:protectionLevel="dangerous"/>
+        android:protectionLevel="signatureOrSystem"/>
 
     <!-- @hide Allows an application to Access UCE-OPTIONS.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
         android:permissionGroup="android.permission-group.PHONE"
-        android:protectionLevel="dangerous"/>
+        android:protectionLevel="signatureOrSystem"/>
 
 
 
@@ -2004,6 +2004,11 @@
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows but does not guarantee access to user passwords at the conclusion of add
+         account -->
+    <permission android:name="android.permission.GET_PASSWORD_PRIVILEGED"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows applications to RW to diagnostic resources.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DIAGNOSTIC"
@@ -2172,6 +2177,15 @@
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
+     to ensure that only the system can bind to it.
+     @hide
+     @SystemApi
+     <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
+            android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
          the system can bind to it.
@@ -2975,6 +2989,11 @@
     <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to whitelist tasks during lock task mode
+         @hide <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
+        android:protectionLevel="signature|setup" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -2984,7 +3003,7 @@
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true"
-                 android:theme="@style/Theme.Material.DayNight.DarkActionBar"
+                 android:theme="@style/Theme.Material.Light.DarkActionBar"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
@@ -3020,7 +3039,7 @@
                 android:label="@string/managed_profile_label">
         </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/heavy_weight_switcher_title"
                 android:finishOnCloseSystemDialogs="true"
                 android:excludeFromRecents="true"
@@ -3053,7 +3072,7 @@
         <activity android:name="android.accounts.ChooseAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
@@ -3061,14 +3080,14 @@
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                 android:excludeFromRecents="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog"
+                android:theme="@style/Theme.Material.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
@@ -3076,19 +3095,19 @@
         <activity android:name="android.accounts.CantAddAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.Dialog.NoActionBar"
+                android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.DayNight.DialogWhenLarge"
+                android:theme="@style/Theme.Material.Light.DialogWhenLarge"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
-               android:theme="@style/Theme.Material.DayNight.Dialog"
+               android:theme="@style/Theme.Material.Light.Dialog"
                android:label="@string/sync_too_many_deletes"
                android:process=":ui">
         </activity>
@@ -3108,7 +3127,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                android:theme="@style/Theme.Material.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
@@ -3129,7 +3148,7 @@
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
                 android:excludeFromRecents="true"
                 android:process=":ui"
-                android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+                android:theme="@style/Theme.Material.Light.Dialog.Alert">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3137,7 +3156,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                android:theme="@style/Theme.Material.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
diff --git a/core/res/res/anim/slide_in_micro.xml b/core/res/res/anim/slide_in_enter_micro.xml
similarity index 67%
rename from core/res/res/anim/slide_in_micro.xml
rename to core/res/res/anim/slide_in_enter_micro.xml
index 6320e80..14a5290 100644
--- a/core/res/res/anim/slide_in_micro.xml
+++ b/core/res/res/anim/slide_in_enter_micro.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/slide_in_micro.xml
 **
 ** Copyright 2014, The Android Open Source Project
 **
@@ -18,10 +17,13 @@
 */
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-    <translate android:fromXDelta="100%p" android:toXDelta="0"
-               android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:zAdjustment="top">
+    <translate android:fromYDelta="5%p" android:toXDelta="0"
+               android:duration="417"
+               android:interpolator="@android:interpolator/launch_task_micro_ydelta" />
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-           android:duration="@android:integer/config_mediumAnimTime" />
+           android:duration="150"
+           android:interpolator="@android:interpolator/launch_task_micro_alpha" />
 </set>
diff --git a/core/res/res/anim/slide_in_exit_micro.xml b/core/res/res/anim/slide_in_exit_micro.xml
new file mode 100644
index 0000000..f0d8c0b
--- /dev/null
+++ b/core/res/res/anim/slide_in_exit_micro.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:duration="417" />
+</set>
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index 4cb6df0..c647093 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -18,10 +18,13 @@
 */
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-    <translate android:fromXDelta="0" android:toXDelta="100%p"
-               android:duration="@android:integer/config_mediumAnimTime"/>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:zAdjustment="top">
+    <translate android:fromYDelta="0" android:toYDelta="5%p"
+               android:duration="250"
+               android:interpolator="@android:interpolator/fast_out_slow_in"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-           android:duration="@android:integer/config_mediumAnimTime" />
+           android:startOffset="100" android:duration="150"
+           android:interpolator="@android:interpolator/fast_out_slow_in" />
 </set>
diff --git a/core/res/res/interpolator/launch_task_micro_alpha.xml b/core/res/res/interpolator/launch_task_micro_alpha.xml
new file mode 100644
index 0000000..41b79b5
--- /dev/null
+++ b/core/res/res/interpolator/launch_task_micro_alpha.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0"
+                  android:controlY1="0"
+                  android:controlX2="0.7"
+                  android:controlY2="1" />
diff --git a/core/res/res/interpolator/launch_task_micro_ydelta.xml b/core/res/res/interpolator/launch_task_micro_ydelta.xml
new file mode 100644
index 0000000..acac761
--- /dev/null
+++ b/core/res/res/interpolator/launch_task_micro_ydelta.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:controlX1="0"
+                  android:controlY1="0"
+                  android:controlX2="0.4"
+                  android:controlY2="1" />
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 9f50937..6d33de6 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -34,7 +34,6 @@
             android:id="@+id/scrollView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="@dimen/dialog_padding_top_material"
             android:clipToPadding="false">
 
             <LinearLayout
@@ -42,6 +41,12 @@
                 android:layout_height="wrap_content"
                 android:orientation="vertical">
 
+                <Space
+                    android:id="@+id/textSpacerNoTitle"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_padding_top_material" />
+
                 <TextView
                     android:id="@+id/message"
                     android:layout_width="match_parent"
@@ -53,7 +58,7 @@
                 <Space
                     android:id="@+id/textSpacerNoButtons"
                     android:visibility="gone"
-                    android:layout_width="0dp"
+                    android:layout_width="match_parent"
                     android:layout_height="@dimen/dialog_padding_top_material" />
             </LinearLayout>
         </ScrollView>
diff --git a/core/res/res/layout/alert_dialog_title_material.xml b/core/res/res/layout/alert_dialog_title_material.xml
index 738a637..eef9585 100644
--- a/core/res/res/layout/alert_dialog_title_material.xml
+++ b/core/res/res/layout/alert_dialog_title_material.xml
@@ -21,6 +21,8 @@
               android:layout_height="wrap_content"
               android:orientation="vertical">
 
+    <!-- If the client uses a customTitle, it will be added here. -->
+
     <LinearLayout
         android:id="@+id/title_template"
         android:layout_width="match_parent"
@@ -49,5 +51,9 @@
             style="?attr/windowTitleStyle" />
     </LinearLayout>
 
-    <!-- If the client uses a customTitle, it will be added here. -->
+    <Space
+        android:id="@+id/titleDividerNoCustom"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dialog_title_divider_material" />
 </LinearLayout>
diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
index 8bef116..5ad0f4c 100644
--- a/core/res/res/layout/app_anr_dialog.xml
+++ b/core/res/res/layout/app_anr_dialog.xml
@@ -19,7 +19,7 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingTop="@dimen/aerr_padding_list_top"
-        android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+        android:paddingBottom="@dimen/aerr_padding_list_bottom">
 
     <Button
             android:id="@+id/aerr_close"
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index b9531f4..7147ea2 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -22,7 +22,7 @@
         android:layout_height="wrap_content"
         android:orientation="vertical"
         android:paddingTop="@dimen/aerr_padding_list_top"
-        android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
+        android:paddingBottom="@dimen/aerr_padding_list_bottom">
 
 
     <Button
diff --git a/core/res/res/layout/select_dialog_material.xml b/core/res/res/layout/select_dialog_material.xml
index 19ad407..9a068f9a 100644
--- a/core/res/res/layout/select_dialog_material.xml
+++ b/core/res/res/layout/select_dialog_material.xml
@@ -30,6 +30,6 @@
     android:scrollbars="vertical"
     android:overScrollMode="ifContentScrolls"
     android:textAlignment="viewStart"
-    android:paddingTop="@dimen/dialog_list_padding_vertical_material"
-    android:paddingBottom="@dimen/dialog_list_padding_vertical_material"
-    android:clipToPadding="false" />
+    android:clipToPadding="false"
+    android:paddingBottomNoButtons="@dimen/dialog_list_padding_bottom_no_buttons"
+    android:paddingTopNoTitle="@dimen/dialog_list_padding_top_no_title" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 1f958b4..7ca52a3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek volgens beleid"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Geen toestemmings benodig nie"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dit kan jou dalk geld kos"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB vir batterylaai"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB laai tans hierdie toestel"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB verskaf tans krag aan gekoppelde toestel"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB vir lêeroordrag"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB vir foto-oordrag"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB vir MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Ander sleutelborde"</string>
     <string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
     <string name="hardware" msgid="194658061510127999">"Wys virtuele sleutelbord"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Kies sleutelborduitleg"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Raak om \'n sleutelborduitleg te kies."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2623053..200ec30 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ይዘቶች በመመሪያ ተደብቀዋል"</string>
     <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"የግል"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"ስራ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ዕውቂያዎች"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"የእርስዎ እውቂያዎች ላይ ይድረሱባቸው"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"መገኛ አካባቢ"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎት ይችላል"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"እሺ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ዩኤስቢ ለኃይል መሙላት"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ዩኤስቢ የዚህን መሣሪያ ኃይል በመሙላት ላይ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ዩኤስቢ ለተያያዘው መሣሪያ ኃይል በማቅረብ ላይ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ዩኤስቢ ለፋይል ሽግግር"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ዩኤስቢ ለፎቶ ሽግግር"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"ዩኤስቢ ለMIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"ሌሎች ቁልፍ ሰሌዳዎች"</string>
     <string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
     <string name="hardware" msgid="194658061510127999">"ምናባዊ የቁልፍ ሰሌዳን አሳይ"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"የቁልፍ ሰሌዳ አቀማመጥ ምረጥ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"የቁልፍ ሰሌዳ አቀማመጥ ለመምረጥ ንካ።"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b828197..d812787 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -241,8 +241,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"تم إخفاء المحتويات بواسطة السياسة"</string>
     <string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏نظام Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"شخصي"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"عمل"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"جهات الاتصال"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"الوصول إلى جهات اتصالك"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"الموقع"</string>
@@ -1077,7 +1079,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"لا أذونات مطلوبة"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"قد يكلفك هذا مالاً."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"موافق"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏USB للشحن"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏يتم استخدام الاتصال عبر USB لشحن هذا الجهاز"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏يتم استخدام الاتصال عبر USB لإمداد الجهاز المتصل بالطاقة"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB لنقل الملفات"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏USB لنقل الصور"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB لـ MIDI"</string>
@@ -1095,8 +1098,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"لوحات المفاتيح الأخرى"</string>
     <string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
     <string name="hardware" msgid="194658061510127999">"إظهار لوحة المفاتيح الظاهرية"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"تحديد تخطيط لوحة مفاتيح"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"المس لتحديد تخطيط لوحة مفاتيح."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 25a979b..5479958 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Məzmun siyasət tərəfindən gizlədilib"</string>
     <string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Şəxsi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarınıza daxil olun"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Yer"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Heç bir icazə tələb olunmur"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"bununla sizdən xərc tutula bilər"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Enerji doldurmaq üçün USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB bu cihaza enerji doldurur"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Qolulmuş cihaz üçün USB enerji tədarükü"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fayl transferi üçün USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Foto transfer üçün USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI üçün USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Digər klaviaturalar"</string>
     <string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
     <string name="hardware" msgid="194658061510127999">"Virtual klaviaturanı göstərin"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatura sxemi seçin"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Klaviatura tərtibatı seçmək üçün toxunun."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 3eff6f3..9f9b5b8 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je sakriven smernicama"</string>
     <string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupi kontaktima"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1053,7 +1055,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nije potrebna nijedna dozvola"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ovo će vam možda biti naplaćeno"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Potvrdi"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB puni ovaj uređaj"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB snabdeva energijom priključeni uređaj"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datoteka"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos slika"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1071,8 +1074,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Druge tastature"</string>
     <string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izbor rasporeda tastature"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite da biste izabrali raspored tastature."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index 7b85628..6848fda 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Змесціва, схаванае ў адпаведнасці з палітыкай"</string>
     <string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Асабістыя"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Працоўны"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Кантакты"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"атрымліваць доступ да вашых кантактаў"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Месцазнаходжанне"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"за гэта можа спаганяцца плата"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB для зарадкі"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Зарадка гэтай прылады па USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Падача сілкавання падключанай прыладзе па USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перадачы файлаў"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перадачы фота"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Іншыя праграмныя клавіятуры"</string>
     <string name="show_ime" msgid="2506087537466597099">"Захоўваць яе на экране ў той час, калі фізічная клавіятура актыўная"</string>
     <string name="hardware" msgid="194658061510127999">"Паказаць віртуальную клавіятуру"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Выбраць раскладку клавіятуры"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Націсніце, каб выбраць раскладку клавіятуры."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4515e80..4f8f80c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Съдържанието е скрито чрез правило"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Личен"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Служебен"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"има достъп до контактите ви"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Не се изискват разрешения"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"това може да ви струва пари"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB за зареждане"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"През USB се зарежда това устройство"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"През USB се зарежда свързаното устройство"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB за прехвърляне на файлове"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB за прехвърляне на снимки"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Други клавиатури"</string>
     <string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
     <string name="hardware" msgid="194658061510127999">"Показване на вирт. клавиатура"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избиране на клавиатурна подредба"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Докоснете, за да изберете клавиатурна подредба."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 03faf2f..13284cf 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"নীতির কারণে সামগ্রী লুকানো আছে"</string>
     <string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ব্যক্তিগত"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"কর্মক্ষেত্র"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"পরিচিতি"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"আপনার পরিচিতিগুলিতে অ্যাক্সেস করুন"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"অবস্থান"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"কোনো অনুমতির প্রয়োজন নেই"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"এর জন্য অর্থপ্রদান করতে হতে পারে"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ঠিক আছে"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"চার্জ করার জন্য USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"এই ডিভাইসটি USB দ্বারা চার্জ করা হচ্ছে"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"সংযুক্ত ডিভাইসটিতে USB পাওয়ার সরবরাহ করছে"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ফাইল স্থানান্তরের জন্য USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ফটো স্থানান্তরের জন্য USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI এর জন্য USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"অন্যান্য কীবোর্ড"</string>
     <string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
     <string name="hardware" msgid="194658061510127999">"ভার্চুয়াল কীবোর্ড দেখান"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"কীবোর্ডের লেআউট নির্বাচন করুন"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"একটি কীবোর্ডের লেআউট নির্বাচন করতে স্পর্শ করুন৷"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 7e9f44f..bbc72d5 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj skriven u skladu sa pravilima"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Poslovni"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupa vašim kontaktima"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1053,7 +1055,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nisu potrebne dozvole"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ovo se možda dodatno plaća"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Uredu"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Ovaj uređaj se puni preko USB-a"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB napaja priključeni uređaj"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos fajlova"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos slika"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1071,8 +1074,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Ostale tastature"</string>
     <string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tastaturu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite raspored tastature"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir rasporeda tastature."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e59c936..07ba682 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contingut amagat de conformitat amb la política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Feina"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactes"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedir als contactes"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ubicació"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"pot ser que comporti càrrecs"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"D\'acord"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB per carregar"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"L\'USB està carregant el dispositiu"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"L\'USB subministra energia al dispositiu inserit"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per transferir fitxers"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per transferir fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per a MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Altres teclats"</string>
     <string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
     <string name="hardware" msgid="194658061510127999">"Mostra el teclat virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona una disposició de teclat"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca per seleccionar una disposició de teclat."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 237d44d..0a9aa2b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah skrytý zásadami"</string>
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobní"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Práce"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"může vás to něco stát"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB na nabíjení"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Nabíjení zařízení přes USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Připojené zařízení se nabíjí přes USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB na přenos souborů"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB na přenos fotek"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB v režimu MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Další klávesnice"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
     <string name="hardware" msgid="194658061510127999">"Zobrazit virtuální klávesnici"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Výběr rozložení klávesnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotykem vyberte rozložení klávesnice."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 391b012..dd2d223 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Indholdet er skjult af politikken"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Arbejde"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersoner"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste dig penge"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB til opladning"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB, der oplader denne enhed"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, der leverer strøm til den tilsluttede enhed"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB til filoverførsel"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB til billedoverførsel"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB til MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Andre tastaturer"</string>
     <string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
     <string name="hardware" msgid="194658061510127999">"Vis virtuelt tastatur"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Vælg tastaturlayout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tryk for at vælge et tastaturlayout."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d95bdda..b32bea6 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhalte aufgrund der Richtlinien ausgeblendet"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Privat"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Geschäftlich"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"auf Kontakte zuzugreifen"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Hierfür können Gebühren anfallen."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB zum Aufladen"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gerät wird über USB aufgeladen"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Angeschlossenes Gerät wird über USB aufgeladen"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB für die Dateiübertragung"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB für die Fotoübertragung"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB für MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Weitere Tastaturen"</string>
     <string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuelle Tastatur einblenden"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Tastaturlayout auswählen"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Zum Auswählen eines Tastaturlayouts berühren"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ce0805f..71351a3 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Το περιεχόμενο είναι κρυφό βάσει πολιτικής"</string>
     <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Προσωπικό"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Εργασία"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Επαφές"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"πρόσβαση στις επαφές σας"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Τοποθεσία"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτούνται άδειες"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ενδέχεται να χρεωθείτε"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ΟΚ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB για φόρτιση"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Αυτή η συσκευή φορτίζεται μέσω USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Η συνδεδεμένη συσκευή τροφοδοτείται μέσω USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB για μεταφορά αρχείων"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB για μεταφορά φωτογραφιών"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB για MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Άλλα πληκτρολόγια"</string>
     <string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
     <string name="hardware" msgid="194658061510127999">"Εμφάνιση εικονικού πληκτρολ."</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Επιλογή διάταξης πληκτρολογίου"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Αγγίξτε για να επιλέξετε διάταξη πληκτρολογίου."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 335f1f0..c222397 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
     <string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
     <string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 335f1f0..c222397 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
     <string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
     <string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 335f1f0..c222397 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"access your contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Location"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"this may cost you money"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for charging"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB charging this device"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB supplying power to attached device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for file transfer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for photo transfer"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Other keyboards"</string>
     <string name="show_ime" msgid="2506087537466597099">"Keep it on screen while physical keyboard is active"</string>
     <string name="hardware" msgid="194658061510127999">"Show virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Select keyboard layout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Touch to select a keyboard layout."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 27cd9d2..afd5f6c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenido oculto debido a la política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a los contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"esto puede costarte dinero"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB solo para realizar cargas"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Este dispositivo se está cargando mediante USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado se está cargando mediante USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Otros teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6521cca..3d5682c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenidos ocultos por política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder a tus contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ubicación"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"es posible que esto te cueste dinero"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para cargar"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cargando este dispositivo por USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado recibe la alimentación por USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Otros teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecciona un diseño de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un diseño de teclado."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 3905a55..7b2e108 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisu on eeskirjadega peidetud"</string>
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Isiklik"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Töö"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktid"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"juurdepääs kontaktidele"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Asukoht"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Lube pole vaja"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"see võib olla tasuline"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB laadimiseks"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Laadimiseks ühendage USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Ühendatud seade saab toidet USB kaudu"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB failide edastamiseks"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fotode edastamiseks"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI jaoks"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Muud klaviatuurid"</string>
     <string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuaalse klaviatuuri kuvam."</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klaviatuuri paigutuse valimine"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Puudutage klaviatuuri paigutuse valimiseks."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 8b8f29f..5bcaed1 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Gidalerro batzuk ezkutatu dira, gidalerroei jarraiki"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Lana"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Ez da baimenik behar"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dirua kosta dakizuke"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Ados"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Kargatzeko USBa"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gailua USB bidez ari da kargatzen"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Konektatutako gailua USB bidez jasotzen ari da energia"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fitxategiak transferitzeko USBa"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Argazkiak transferitzeko USBa"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI modurako USBa"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Beste teklatu batzuk"</string>
     <string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
     <string name="hardware" msgid="194658061510127999">"Erakutsi teklatu birtuala"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Hautatu teklatuaren diseinua"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Ukitu teklatuaren diseinua hautatzeko."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e67e058..7688af4 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"محتوا بر اساس خط‌مشی پنهان شده است"</string>
     <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏سیستم Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"شخصی"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"محل کار"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"مخاطبین"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"دسترسی به مخاطبین شما"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"مکان"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ممکن است برای شما هزینه داشته باشد"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏USB برای شارژ کردن"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏شارژ کردن این دستگاه از طریق USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏شارژ دستگاه متصل از طریق USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB برای انتقال فایل"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏USB برای انتقال عکس"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB برای MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"صفحه‌کلیدهای دیگر"</string>
     <string name="show_ime" msgid="2506087537466597099">"وقتی صفحه‌کلید فیزیکی فعال است این ویرایشگر را روی صفحه نگه‌می‌دارد"</string>
     <string name="hardware" msgid="194658061510127999">"نمایش صفحه‌کلید مجازی"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"انتخاب طرح‌بندی صفحه‌کلید"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"برای انتخاب یک طرح‌بندی صفحه‌کلید لمس کنید…"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b1ad7e7..9105842 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisältö on piilotettu käytännön perusteella."</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Henkilökoht."</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktit"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"käyttää yhteystietoja"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Sijainti"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Lupia ei tarvita"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"tämä voi maksaa"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB on lataustilassa"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Laitetta ladataan USB-yhteyden kautta"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Liitetty laite saa virtaa USB-yhteyden kautta"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB on tiedonsiirtotilassa"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB on kuvansiirtotilassa"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB on MIDI-tilassa"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Muut näppäimistöt"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
     <string name="hardware" msgid="194658061510127999">"Näytä virtuaalinen näppäimistö"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Valitse näppäimistöasettelu"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kosketa ja valitse näppäimistöasettelu."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 09993ac..222501f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux politiques"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Travail"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localisation"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"cela peut engendrer des frais"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB pour la recharge"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cet appareil est en cours de charge par USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Un connecteur USB alimente cet appareil"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB pour le transfert de fichiers"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB pour le transfert de photos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB pour MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Autres claviers"</string>
     <string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
     <string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Sélectionnez la disposition du clavier"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Appuyez ici pour sélectionner une disposition de clavier."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 30ff9fb..1b8e03c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux règles"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Professionnel"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accéder à vos contacts"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Position"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Cela peut engendrer des frais"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Recharge par USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Recharge via USB de cet appareil…"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Alimentation via USB de l\'appareil connecté…"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB pour le transfert de fichiers"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB pour le transfert de photos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB en mode MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Autres claviers"</string>
     <string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
     <string name="hardware" msgid="194658061510127999">"Afficher le clavier virtuel"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Sélectionnez la disposition du clavier"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Appuyez ici pour sélectionner une disposition de clavier."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 0d479a5..ae5cc61 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Ocultouse contido por causa da política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Traballo"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Non é necesario ningún permiso"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"é posible que teñas que pagar"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carga"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"O USB está cargando este dispositivo"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"O USB está proporcionando enerxía ao dispositivo conectado"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferencia de ficheiros"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferencia de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleccionar deseño de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toca para seleccionar un deseño de teclado."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 4389cff..0487612 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"નીતિ દ્વારા સામગ્રી છુપાવાઈ"</string>
     <string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"વ્યક્તિગત"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"કાર્યાલય"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"કોઈ પરવાનગીઓ જરૂરી નથી"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"આનાથી તમારા પૈસા ખર્ચ થઈ શકે છે"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ઑકે"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ચાર્જ કરવા માટે USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"આ ઉપકરણને USB થી ચાર્જ કરે છે"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"જોડાયેલ ઉપકરણ માટે USB પાવર પૂરો પાડે છે"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ફાઇલ ટ્રાન્સફર માટે USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ફોટા ટ્રાન્સફર માટે USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI માટે USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"અન્ય કીબોર્ડ્સ"</string>
     <string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
     <string name="hardware" msgid="194658061510127999">"વર્ચ્યુઅલ કીબોર્ડ બતાવો"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"કીબોર્ડ લેઆઉટ પસંદ કરો."</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"કીબોર્ડ લેઆઉટ પસંદ કરવા માટે ટચ કરો."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 18c4007..f007f89 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"सामग्री पॉलिसी के द्वारा छिपी हुई है"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"कार्यालय"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"अपने संपर्कों को ऐक्सेस करें"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"किसी अनुमति की आवश्‍यकता नहीं है"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"इससे आपको धन देना पड़ सकता है"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ठीक है"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जिंग के लिए USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"यह डिवाइस USB से चार्ज हो रहा है"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"अटैच किए गए डिवाइस को USB से पावर मिल रही है"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"फ़ाइल स्‍थानांतरण के लिए USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"फ़ोटो स्‍थानांतरण के लिए USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI के लिए USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"अन्य कीबोर्ड"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्‍क्रीन पर बनाए रखें"</string>
     <string name="hardware" msgid="194658061510127999">"वर्चुअल कीबोर्ड दिखाएं"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"कीबोर्ड लेआउट को चुनें"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"कीबोर्ड लेआउट का चयन करने के लिए स्‍पर्श करें."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bc74c9d..af8de3f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je skriven prema pravilima"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobno"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupati vašim kontaktima"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1053,7 +1055,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nije potrebno dopuštenje"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"možda ćete morati platiti"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"U redu"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Punjenje uređaja USB-om"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Napajanje priključenog uređaja USB-om"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prijenos datoteka"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos fotografija"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1071,8 +1074,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Ostale tipkovnice"</string>
     <string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtualnu tipkovnicu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Odaberite izgled tipkovnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite za odabir izgleda tipkovnice."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index bf23b71..6ae5120 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"A tartalom irányelv miatt elrejtve"</string>
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Személyes"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Munkahelyi"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Névjegyek"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"hozzáférés a névjegyekhez"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Helyadatok"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nincs szükség engedélyre"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ez pénzbe kerülhet Önnek"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB töltéshez"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Az eszköz USB-s töltése"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"A csatlakoztatott eszköz USB-n keresztül való töltése"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB fájlátvitelhez"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fotóátvitelhez"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-hez"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Más billentyűzetek"</string>
     <string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuális billentyűzet"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Válasszon billentyűzetkiosztást"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Érintse meg az egyik billentyűzetkiosztás kiválasztásához."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 030975e..1a4a2eb 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Բովանդակությունը թաքցվել է ըստ քաղաքականության"</string>
     <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Անձնական"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Աշխատանքային"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Կոնտակտներ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"կոնտակտների հասանելիություն"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Տեղադրություն"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Թույլտվություններ չեն պահանջվում"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Սա կարող է գումար պահանջել"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Լավ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Լիցքավորման USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Սարքի լիցքավորում USB լարի միջոցով"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Հոսանքի մատակարարում կցված սարքերին USB լարի միջոցով"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Ֆայլերի փոխանցման USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Լուսանկարների փոխանցման USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ի USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Այլ ստեղնաշարեր"</string>
     <string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
     <string name="hardware" msgid="194658061510127999">"Ցույց տալ վիրտուալ ստեղնաշարը"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Ընտրեք ստեղնաշարի դիրքը"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Հպեք` ստեղնաշարի դիրքը ընտրելու համար:"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 819ea80..480a845 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Konten disembunyikan menurut kebijakan"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pribadi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Kantor"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontak"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kontak"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Tidak perlu izin"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ini mungkin tidak gratis"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Oke"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB untuk pengisian daya"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Mengisi daya perangkat ini melalui USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Menyuplai daya melalui USB ke perangkat yang terpasang"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk transfer file"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk transfer foto"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Keyboard lainnya"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pertahankan di layar jika keyboard fisik masih aktif"</string>
     <string name="hardware" msgid="194658061510127999">"Tampilkan keyboard virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih tata letak keyboard"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih tata letak keyboard."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 91624e7..ce00b09 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Efni falið með reglu"</string>
     <string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persónulegt"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Vinna"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Tengiliðir"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"fá aðgang að tengiliðunum þínum"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Staðsetning"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Engra heimilda þörf"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"þú gætir þurft að borga fyrir þetta"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Í lagi"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB fyrir hleðslu"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Þetta tæki er í USB-hleðslu"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Tengt tæki er í USB-hleðslu"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB fyrir skráaflutning"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB fyrir myndaflutning"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB fyrir MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Önnur lyklaborð"</string>
     <string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
     <string name="hardware" msgid="194658061510127999">"Sýna sýndarlyklaborð"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Veldu lyklaskipan"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Snertu til að velja lyklaskipan."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9937e0d..19fcf55 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenuti nascosti in base alle norme"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personale"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Lavoro"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatti"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"accedere ai contatti"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Posizione"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"potrebbe comportare dei costi"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB per la ricarica"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dispositivo in carica tramite USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Dispositivo collegato alimentato tramite USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB per il trasferimento di file"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB per il trasferimento di foto"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per la modalità MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Altre tastiere"</string>
     <string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
     <string name="hardware" msgid="194658061510127999">"Mostra tastiera virtuale"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleziona layout tastiera"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tocca per selezionare un layout di tastiera."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 443c1be..41acce9 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"התוכן מוסתר על ידי המדיניות"</string>
     <string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏מערכת Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"אישי"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"עבודה"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"אנשי קשר"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"גישה אל אנשי הקשר"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"מיקום"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"לא דרושים אישורים"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"פעולה זו עשויה לחייב אותך בכסף:"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"אישור"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏USB לטעינה"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏USB טוען את המכשיר הזה"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏USB מספק מתח למכשיר המצורף"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB להעברת קבצים"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏USB להעברת תמונות"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB ל-MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"מקלדות אחרות"</string>
     <string name="show_ime" msgid="2506087537466597099">"השאר אותו במסך בזמן שהמקלדת הפיזית פעילה"</string>
     <string name="hardware" msgid="194658061510127999">"הצג מקלדת וירטואלית"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"בחירת פריסת מקלדת"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"גע כדי לבחור פריסת מקלדת."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e81beb3..dff30b4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ポリシーによって非表示になっているコンテンツ"</string>
     <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"個人用"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"仕事用"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"連絡先"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"連絡先へのアクセス"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置情報"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"権限の許可は必要ありません"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"料金が発生する場合があります"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USBを充電に使用"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"この端末を USB で充電"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"接続した端末に USB で給電"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USBをファイル転送に使用"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USBを写真転送に使用"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USBをMIDIに使用"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"その他のキーボード"</string>
     <string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
     <string name="hardware" msgid="194658061510127999">"仮想キーボードの表示"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"キーボードレイアウトの選択"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"タップしてキーボードレイアウトを選択してください。"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 3e463f1..eaed9dd9 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"შიგთავსი დამალულია წესების შესაბამისად"</string>
     <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"პირადი"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"სამსახური"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"კონტაქტები"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"თქვენს კონტაქტებზე წვდომა"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"მდებარეობა"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ნებართვა საჭირო არ არის"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ამისათვის შესაძლოა მოგიწიოთ თანხის გადახდა"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB დამუხტვისთვის"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"მოწყობილობა USB-ის მეშვეობით იტენება"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"მიერთებულ მოწყობილობას ელკვებას USB აწვდის"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB ფაილების გადაცემისთვის"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB ფოტოების გადაცემისთვის"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-სთვის"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"სხვა კლავიატურები"</string>
     <string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
     <string name="hardware" msgid="194658061510127999">"ვირტუალური კლავიატურის ჩვენება"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"შეარჩიეთ კლავიატურის განლაგება."</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"კლავიატურის განლაგების შესარჩევად შეეხეთ."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 342db02..aecf49f 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Мазмұн саясатқа сай жасырылған"</string>
     <string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Жұмыс"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Рұқсат қажет емес"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"бұған төлем қажет болуы мүмкін"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Жарайды"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Зарядтауға арналған USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB арқылы зарядтау"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB жалғанған құрылғыға қуат беруде"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файлды тасымалдауға арналған USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Фотосуретті тасымалдауға арналған USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI режиміне арналған USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Басқа пернетақталар"</string>
     <string name="show_ime" msgid="2506087537466597099">"Физикалық пернетақта белсенді кезде оны экранда ұстау"</string>
     <string name="hardware" msgid="194658061510127999">"Виртуалды пернетақтаны көрсету"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Пернетақта орналасуын таңдау"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Пернетақта орналасуын таңдау үшін түртіңіз."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index fdee3aa..fb80d6e 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"មាតិកាត្រូវបានលាក់ដោយផ្អែកលើគោលការណ៍"</string>
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ​​ Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"កន្លែង​ធ្វើ​ការ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ទំនាក់ទំនង"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ចូលប្រើទំនាក់ទំនងរបស់អ្នក"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ទីតាំង"</string>
@@ -1047,7 +1049,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"មិន​ទាមទារ​សិទ្ធិ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"វា​អាច​កាត់​លុយ​​អ្នក"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"យល់ព្រម"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB សម្រាប់បញ្ចូលថ្ម"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB កំពុងសាកឧបករណ៍នេះ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB កំពុងផ្គត់ផ្គង់ថាមពលទៅឧបករណ៍ដែលបានភ្ជាប់"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB សម្រាប់ការផ្ទេរឯកសារ"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB សម្រាប់ការផ្ទេររូបថត"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB សម្រាប់ MIDI"</string>
@@ -1065,8 +1068,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"ក្តារចុចផ្សេងទៀត"</string>
     <string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
     <string name="hardware" msgid="194658061510127999">"បង្ហាញក្ដារចុចនិម្មិត"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ជ្រើស​ប្លង់​ក្ដារ​ចុច"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ប៉ះ ​ដើម្បី​ជ្រើស​ប្លង់​​ក្ដារចុច។"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index b31b2bb..f2e5024 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ನೀತಿಯಿಂದ ಮರೆಮಾಡಲಾಗಿರುವ ವಿಷಯಗಳು"</string>
     <string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ವೈಯಕ್ತಿಕ"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"ಕಚೇರಿ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ಸಂಪರ್ಕಗಳು"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ಸ್ಥಳ"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ಯಾವುದೇ ಅನುಮತಿಗಳ ಅಗತ್ಯವಿಲ್ಲ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ಇದು ನಿಮ್ಮ ಹಣವನ್ನು ವ್ಯಯಿಸಬಹುದು"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ಸರಿ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ಚಾರ್ಜ್ ಮಾಡುವುದಕ್ಕಾಗಿ USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ಈ ಸಾಧನಕ್ಕೆ USB ಅನ್ನು ಚಾರ್ಜ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, ಲಗತ್ತಿಸಲಾದ ಸಾಧನಕ್ಕೆ ಪವರ್‌ ಪೂರೈಸುತ್ತಿದೆ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ಫೈಲ್‌ ವರ್ಗಾವಣೆಗೆ USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ಫೋಟೋ ವರ್ಗಾವಣೆಗೆ USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ಗೆ USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"ಇತರೆ ಕೀಬೋರ್ಡ್‌ಗಳು"</string>
     <string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
     <string name="hardware" msgid="194658061510127999">"ವರ್ಚ್ಯುಯಲ್ ಕೀಬೋರ್ಡ್ ತೋರಿಸು"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆಯ್ಕೆ ಮಾಡಲು ಸ್ಪರ್ಶಿಸಿ"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 51418d9..dc69ee9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"콘텐츠가 정책에 의해 숨겨졌습니다."</string>
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"개인"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"직장"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"권한 필요 없음"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"비용이 부과될 수 있습니다."</string>
     <string name="dlg_ok" msgid="7376953167039865701">"확인"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"충전용 USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"이 기기를 USB로 충전"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"연결된 기기에 USB로 전력 공급"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"파일 전송용 USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"사진 전송용 USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI용 USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"기타 키보드"</string>
     <string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
     <string name="hardware" msgid="194658061510127999">"가상 키보드 표시"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"키보드 레이아웃 선택"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"터치하여 키보드 레이아웃을 선택합니다."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 32f3d9a..03951a4 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Тийиштүү саясат боюнча жашырылган мазмундар"</string>
     <string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Жумуш"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
@@ -1046,7 +1048,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Эч уруксаттын кереги жок"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"бул үчүн акы алынышы мүмкүн"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Жарайт"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Кубаттоо үчүн USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Бул түзмөк USB менен кубатталууда"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Тиркелген түзмөк USB менен кубатталууда"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файл өткөрүү үчүн USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Сүрөт өткөрүү үчүн USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI үчүн USB"</string>
@@ -1064,8 +1067,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Башка баскычтоптор"</string>
     <string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
     <string name="hardware" msgid="194658061510127999">"Виртуалдык баскычтоп"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Тергичтин жайгашуусун тандоо"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Тергичтин жайгашуусун тандаш үчүн басыңыз."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
@@ -1225,7 +1230,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Дагы параметрлер"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"Бөлүшүлгөн ички сактагыч"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Жалпы ички сактагыч"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD карта"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB түзмөк"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 94fb2db..f64f8df 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ເນື້ອຫາຖືກເຊື່ອງຕາມນະໂຍບາຍ"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"​ສ່ວນ​ໂຕ"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"​ບ່ອນ​ເຮັດ​ວຽກ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ລາຍຊື່"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ເຂົ້າ​ຫາ​ລາຍ​ຊື່​ຂອງ​ທ່ານ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ສະ​ຖານ​ທີ່"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ບໍ່ຕ້ອງການການອະນຸຍາດ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ລາຍການນີ້ອາດມີການເກັບເງິນ"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ຕົກລົງ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB ສຳ​ລັບ​ການ​ສາກ"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ກຳລັງສາກໄຟ USB ອຸປະກອນນີ້"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB ກຳລັງສະໜອງໄຟໃຫ້ກັບອຸປະກອນທີ່ເຊື່ອມຕໍ່ກັນ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB ສຳ​ລັບ​ການ​ໂອ​ນ​ໄຟ​ລ໌"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB ສຳ​ລັບ​ການ​ໂອນ​ໄຟ​ລ໌"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB ສຳ​ລັບ MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"ແປ້ນພິມອື່ນໆ"</string>
     <string name="show_ime" msgid="2506087537466597099">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
     <string name="hardware" msgid="194658061510127999">"ສະແດງແປ້ນພິມສະເໝືອນ"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ເລືອກຮູບແບບແປ້ນພິມ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ກົດເພື່ອເລືອກຮູບແບບແປ້ນພິມ."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c4c4fa2..517a069 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Turinys paslėptas vadovaujantis politika"</string>
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
     <string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Asmeninė"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Darbo"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktai"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pasiekti kontaktus"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vietovė"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nereikia leidimų"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"tai gali kainuoti"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Gerai"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB (įkrovimas)"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Įrenginys įkraunamas naudojant USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Maitinimas prijungtam įrenginiui tiekiamas naudojant USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB (failų perkėlimas)"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB (nuotraukų perkėlimas)"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB (MIDI)"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Kitos klaviatūros"</string>
     <string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
     <string name="hardware" msgid="194658061510127999">"Rodyti virtualiąją klaviatūrą"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pasirinkite klaviatūros išdėstymą"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Palieskite, kad pasirinktumėte klaviatūros išdėstymą."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 566180f..8d8f99b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Saskaņā ar politiku saturs ir paslēpts."</string>
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personisks"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Darba"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersonas"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"piekļūt jūsu kontaktpersonu datiem"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Atrašanās vieta"</string>
@@ -1053,7 +1055,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Atļaujas nav nepieciešamas."</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"par to no jums var tikt iekasēta maksa"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Labi"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB savienojums uzlādei"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB savienojums tiek izmantots šīs ierīces uzlādei"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB savienojums tiek izmantots pievienotās ierīces barošanai"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB savienojums failu pārsūtīšanai"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB savienojums fotoattēlu pārsūtīšanai"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB savienojums MIDI režīmā"</string>
@@ -1071,8 +1074,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Citas tastatūras"</string>
     <string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
     <string name="hardware" msgid="194658061510127999">"Virtuālās tastatūras rādīšana"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Atlasiet tastatūras izkārtojumu"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pieskarieties, lai atlasītu tastatūras izkārtojumu."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index d9dae7a..71c1951 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содржините се скриени поради политиката"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Не се потребни дозволи"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ова може да ве чини пари"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Во ред"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"УСБ за полнење"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Уредов се полни преку USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Прикачениот уред се напојува преку USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"УСБ за пренос на датотеки"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"УСБ за пренос на фотографии"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"УСБ за МИДИ"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Други тастатури"</string>
     <string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелна тастатура"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избери изглед на тастатура"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Допри за да избереш изглед на тастатура."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 16ededc..92f9282 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"നയം അനുസരിച്ച് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string>
     <string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"വ്യക്തിഗതം"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"കോൺടാക്റ്റുകൾ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്‌സസ്സ് ചെയ്യുക"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"അനുമതികളൊന്നും ആവശ്യമില്ല"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ഇത് നിങ്ങൾക്ക് പണച്ചെലവിനിടയാക്കാം"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ശരി"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ചാർജ്ജിംഗിനായുള്ള USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ഈ ഉപകരണം USB ചാർജുചെയ്യുന്നു"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ഘടിപ്പിച്ചിട്ടുള്ള ഉപകരണത്തിന് USB വൈദ്യുതി നൽകുന്നു"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ഫയൽ കൈമാറ്റത്തിനുള്ള USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ഫോട്ടോ കൈമാറ്റത്തിനായുള്ള USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-യ്‌ക്കായുള്ള USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"മറ്റ് കീബോർഡുകൾ"</string>
     <string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
     <string name="hardware" msgid="194658061510127999">"വെർച്വൽ കീബോർഡ് കാണിക്കുക"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ഒരു കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കാൻ സ്‌പർശിക്കുക."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 0f31862..c1cba4f 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Удирдамжийн дагуу нуусан агуулга"</string>
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Ажил"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Харилцагчдын хаяг"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"харилцагч руугаа хандах"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Байршил"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Зөвшөөрөл шаардахгүй"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"Энэ таныг төлбөрт оруулж болзошгүй"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Тийм"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB цэнэглэгч"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Энэ төхөөрөмжийг USB цэнэглэж байна"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Залгасан төхөөрөмжөөс USB цэнэг авч байна"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Файл шилжүүлэх USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Фото зураг шилжүүлэх USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ийн USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Бусад гар"</string>
     <string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
     <string name="hardware" msgid="194658061510127999">"Хийсвэр гарыг харуулах"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Гарын схемийг сонгох"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Гарын схемийг сонгох бол хүрнэ үү."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 9a35efd..f41e6ed 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"धोरणाद्वारे सामग्री लपविली"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"वैयक्तिक"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"कार्य"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"संपर्क"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"आपल्या संपर्कांवर प्रवेश"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"परवानग्या आवश्यक नाहीत"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"यासाठी आपले पैसे खर्च होऊ शकतात"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ठीक"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जिंगसाठी USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB हे डिव्हाइस चार्ज करीत आहे"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करीत आहे"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"स्थानांतरणासाठी USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"फोटो स्थानांतरणासाठी USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI साठी USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"इतर कीबोर्ड"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
     <string name="hardware" msgid="194658061510127999">"व्हर्च्युअल कीबोर्ड दर्शवा"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"कीबोर्ड लेआउट निवडा"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"कीबोर्ड लेआउट निवडण्यासाठी स्पर्श करा."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 7c8ce0f..9a69bf9 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Kandungan disembunyikan oleh dasar"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Tempat Kerja"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kenalan"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"mengakses kenalan anda"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokasi"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Tiada kebenaran diperlukan"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"anda mungkin dikenakan bayaran"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB untuk pengecasan"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Mengecas peranti ini melalui USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Membekalkan kuasa kepada peranti tersambung melalui USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB untuk pemindahan fail"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB untuk pemindahan foto"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Papan kekunci lain"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
     <string name="hardware" msgid="194658061510127999">"Tunjukkan papan kekunci maya"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pilih susun atur papan kekunci"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Sentuh untuk memilih susun atur papan kekunci."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 0c55986..b3c80d5 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"မူဝါဒမှ အကြောင်းအရာများကို ဝှက်ထားသည်"</string>
     <string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ကိုယ်ရေး"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"အလုပ်"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ခွင့်ပြုချက်မလိုအပ်ပါ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"သင့်အတွက် ပိုက်ဆံကုန်ကျနိုင်ပါသည်"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ကောင်းပြီ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"အားသွင်းရန်အတွက် USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB ဖြင့်ဤစက်ပစ္စည်းကို အားသွင်းနေသည်"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ချိတ်ဆက်ထားသည့် စက်ပစ္စည်းကို USB မှတစ်ဆင့် အားသွင်းနေသည်"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ဖိုင်လွှဲပြောင်းရန်အတွက် USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ဓာတ်ပုံလွှဲပြောင်းရန်အတွက် USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI အတွက် USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"အခြားကီးဘုတ်များ"</string>
     <string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
     <string name="hardware" msgid="194658061510127999">"ကီးဘုတ်အတုပြရန်"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"လက်ကွက် အပြင်အဆင်ရွေးရန်"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"လက်ကွက် အပြင်အဆင်ရွေးရန် တို့ထိပါ"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7817321..bebf593 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innholdet er skjult i henhold til retningslinjene"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Jobb"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"se kontaktene dine"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Posisjon"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste deg penger"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB for lading"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Enheten lades via USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Den tilkoblede enheten får strøm via USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB for filoverføring"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB for bildeoverføring"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Andre tastaturoppsett"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
     <string name="hardware" msgid="194658061510127999">"Vis det virtuelle tastaturet"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Velg tastaturoppsett"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Trykk for å velge et tastaturoppsett"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index b6f3c37..24bb1f0 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"नीतिद्वारा लुकाइएका सामग्री"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"काम"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"सम्पर्कहरू"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"तपाईँको सम्पर्कमा पहुँच गर्नुहोस्"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"स्थान"</string>
@@ -1051,7 +1053,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"कुनै अनुमति आवश्यक छैन"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"सायद तपाईँलाई पैसा पर्न सक्छ।"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ठिक छ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"चार्जका लागि USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"यस यन्त्रलाई USB मार्फत चार्ज गर्दै"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"संलग्न गरिएको यन्त्रमा USB मार्फत पावर आपूर्ति गरिँदै"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"फाइल स्थानान्तरणको लागि USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"तस्बिर स्थानान्तरणको लागि USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI को लागि USB"</string>
@@ -1069,8 +1072,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"अन्य किबोर्डहरू"</string>
     <string name="show_ime" msgid="2506087537466597099">"भौतिक किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>
     <string name="hardware" msgid="194658061510127999">"भर्चुअल किबोर्ड देखाउनुहोस्"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"किबोर्ड रूपरेखा चयन गर्नुहोस्"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"किबोर्ड रूपरेखा चयन गर्न टच गर्नुहोस्।"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
deleted file mode 100644
index b344582..0000000
--- a/core/res/res/values-night/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +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.
--->
-
-<!--
-===============================================================
-                        PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
-                        PLEASE READ
-===============================================================
- -->
-<resources>
-
-    <!-- Material theme (day/night version) for activities. -->
-    <style name="Theme.Material.DayNight" parent="Theme.Material" />
-
-    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
-         with an inverse color profile. The dark action bar sharply stands out against
-         the light content (when applicable).  -->
-    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
-
-    <!-- Variant of Material.DayNight with no action bar.  -->
-    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen. This theme
-         sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen and extends into the display overscan region. This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
-
-    <!-- Variant of Material.DayNight that has no title bar and translucent
-         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
-         {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
-
-    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
-         to place your content. It makes the window floating, with a transparent
-         background, and turns off dimming behind the window. -->
-    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
-
-    <!-- Material theme (day/night version) for dialog windows and activities,
-         which is used by the {@link android.app.Dialog} class. This changes
-         the window to be floating (not fill the entire screen), and puts a
-         frame around its contents. You can set this theme on an activity if
-         you would like to make an activity that looks like a Dialog. -->
-    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
-    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
-
-    <!-- Theme for a window that will be displayed either full-screen on
-         smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
-
-    <!-- Theme for a window with a dark action bar that will be displayed
-         either full-screen on smaller screens (small, normal) or as a dialog
-         on larger screens (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.DialogWhenLarge" />
-
-    <!-- Theme for a window without an action bar that will be displayed either full-screen
-         on smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
-
-    <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
-
-    <!-- Material user theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class. -->
-    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
-    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
-
-    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
-    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e8279af7..5759cad 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Persoonlijk"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacten"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"toegang krijgen tot je contacten"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Locatie"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"hieraan kunnen kosten zijn verbonden"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB voor opladen"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dit apparaat wordt opgeladen via USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Het aangesloten apparaat wordt via USB van voeding voorzien"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB voor bestandsoverdacht"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB voor foto-overdracht"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB voor MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Andere toetsenborden"</string>
     <string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
     <string name="hardware" msgid="194658061510127999">"Virtueel toetsenbord tonen"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Toetsenbordindeling selecteren"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tik om een ​​toetsenbordindeling te selecteren."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 8de9102..b984760 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ਨੀਤੀ ਦੁਆਰਾ ਸਮੱਗਰੀ ਲੁਕਾਈ ਗਈ"</string>
     <string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ਨਿੱਜੀ"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"ਕੰਮ"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ਸੰਪਰਕ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਨੂੰ ਐਕਸੈਸ ਕਰੋ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ਕੋਈ ਅਨੁਮਤੀਆਂ ਲੁੜੀਂਦੀਆਂ ਨਹੀਂ"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ਇਸ ਨਾਲ ਤੁਹਾਨੂੰ ਖ਼ਰਚਾ ਪੈ ਸਕਦਾ ਹੈ"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ਠੀਕ"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ਚਾਰਜਿੰਗ ਲਈ USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ਇਹ ਡੀਵਾਈਸ USB ਰਾਹੀਂ ਚਾਰਜ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"ਨੱਥੀ ਕੀਤੀ ਡੀਵਾਈਸ ਨੂੰ USB ਰਾਹੀਂ ਪਾਵਰ ਮਿਲ ਰਹੀ ਹੈ"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ਫ਼ਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ਫੋਟੋ ਟ੍ਰਾਂਸਫ਼ਰ ਲਈ USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ਲਈ USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"ਹੋਰ ਕੀ-ਬੋਰਡ"</string>
     <string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
     <string name="hardware" msgid="194658061510127999">"ਵਰਚੁਅਲ ਕੀ-ਬੋਰਡ ਵਿਖਾਓ"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"ਕੀਬੋਰਡ ਲੇਆਊਟ ਚੁਣੋ"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ਇੱਕ ਕੀਬੋਰਡ ਲੇਆਊਟ ਚੁਣਨ ਲਈ ਛੋਹਵੋ।"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f20e97d..7248f4a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Treść ukryta z powodu zasad"</string>
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
     <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobiste"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Praca"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostęp do kontaktów"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokalizacja"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"to może generować dodatkowe koszty"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB w trybie ładowania"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Ładowanie urządzenia przez USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Zasilanie urządzenia przez USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB w trybie przesyłania plików"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB w trybie przesyłania zdjęć"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB w trybie MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Inne klawiatury"</string>
     <string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
     <string name="hardware" msgid="194658061510127999">"Pokaż klawiaturę wirtualną"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Wybierz układ klawiatury"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Kliknij, by wybrać układ klawiatury."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 2212f9f..bddb0fc 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"isso pode lhe custar dinheiro"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB carregando este dispositivo"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB fornecendo energia ao dispositivo conectado"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de arquivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6cb94c3..68c4bd9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"aceder aos contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Não são necessárias permissões"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"isto poderá estar sujeito a custos"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Carregamento deste dispositivo por USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Fornecimento de energia ao dispositivo ligado por USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de ficheiros"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar o teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecionar esquema de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um esquema de teclado."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2212f9f..bddb0fc 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"isso pode lhe custar dinheiro"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para carregamento"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB carregando este dispositivo"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB fornecendo energia ao dispositivo conectado"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferência de arquivos"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferência de fotos"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Outros teclados"</string>
     <string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
     <string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selecione o layout de teclado"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Toque para selecionar um layout de teclado."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 31ec3a0..58c9383 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conținutul este ascuns conform politicii"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Serviciu"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Persoane de contact"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceseze persoanele de contact"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
@@ -1053,7 +1055,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nu se solicită nicio permisiune"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"aceasta poate să genereze costuri"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Conexiune USB pentru încărcare"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Dispozitivul se încarcă prin USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Dispozitivul atașat se încarcă prin USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Conexiune USB pentru transferul fișierelor"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Conexiune USB pentru transferul fotografiilor"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"Conexiune USB pentru MIDI"</string>
@@ -1071,8 +1074,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Alte tastaturi"</string>
     <string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
     <string name="hardware" msgid="194658061510127999">"Afișați tastatura virtuală"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selectați aspectul tastaturii"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Atingeți pentru a selecta un aspect de tastatură."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5a79523..345bb49 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содержимое скрыто в соответствии с заданными правилами"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Личные данные"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакты"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"доступ к контактам"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Местоположение"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Не требуется разрешений"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"это может стоить вам денег!"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Зарядка через USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Зарядка через USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Подача питания на подключенное устройство через USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Передача файлов через USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Передача фото через USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI через USB"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Другие клавиатуры"</string>
     <string name="show_ime" msgid="2506087537466597099">"Показывать на экране, когда физическая клавиатура включена"</string>
     <string name="hardware" msgid="194658061510127999">"Виртуальная клавиатура"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Выберите раскладку клавиатуры"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Нажмите, чтобы выбрать раскладку клавиатуры."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 4f34cd0..f01ab61 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ප්‍රතිපත්තිය විසින් අන්තර්ගතය සඟවන ලදී"</string>
     <string name="safeMode" msgid="2788228061547930246">"ආරක්‍ෂිත ආකාරය"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"පෞද්ගලික"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"කාර්යාලය"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
@@ -1047,7 +1049,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"අවසර අවශ්‍ය නොමැත"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"මෙමඟින් ඔබට මුදල් වැය විය හැක"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"හරි"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ආරෝපණය කිරීම සඳහා USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"මෙම උපාංගය USB වෙතින් ආරෝපණය"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"අමුණා ඇති උපාංගයට USB මඟින් බලය සපයමින්"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ගොනු හුවමාරුව සඳහා USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ඡායාරූප හුවමාරුව සඳහා USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI සඳහා USB"</string>
@@ -1065,8 +1068,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"වෙනත් යතුරු පුවරු"</string>
     <string name="show_ime" msgid="2506087537466597099">"භෞතික යතුරු පුවරුව සක්‍රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
     <string name="hardware" msgid="194658061510127999">"අතථ්‍ය යතුරු පුවරුව පෙන්වන්න"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"යතුරු පුවරුවට පිරිසැලැස්ම තෝරන්න"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"යතුරු පුවරුවට පිරිසැලැස්මක් තේරීමට ස්පර්ශ කරන්න."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4ba64b1..1a3ef4c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah je na základe pravidiel skrytý"</string>
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osobné"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Práca"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"prístup k vašim kontaktom"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nevyžadujú sa žiadne oprávnenia."</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"môžu sa vám účtovať poplatky"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB na nabíjanie"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Prebieha nabíjanie tohto zariadenia pomocou USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Prebieha nabíjanie pripojeného zariadenia pomocou USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB na prenos súborov"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB na prenos fotiek"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB na pripojenie zariadenia MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Ďalšie klávesnice"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
     <string name="hardware" msgid="194658061510127999">"Zobraziť virtuálnu klávesnicu"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Zvoľte rozloženie klávesnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotykom zvoľte rozloženie klávesnice."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index eb3d4e0..c102abb 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Pravilnik je skril vsebino"</string>
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Osebno"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Služba"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Stiki"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"dostop do stikov"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Ni zahtevanih dovoljenj"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"to je lahko plačljivo"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"V redu"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za polnjenje"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Polnjenje akumulatorja v napravi prek USB-ja"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Napajanje priključene naprave prek USB-ja"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datotek"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos fotografij"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Druge tipkovnice"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
     <string name="hardware" msgid="194658061510127999">"Pokaži navidezno tipkovnico"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izberite razporeditev tipkovnice"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dotaknite se, da izberete razporeditev tipkovnice"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 94258e2..9151893 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Përmbajtja është e fshehur për shkak të politikës"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Puna"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Nuk kërkohen leje"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"kjo mund të të kushtojë para"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Në rregull"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB-ja për ngarkim"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Kjo pajisje ngarkohet me USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Pajisja e lidhur furnizohet me enrgji me USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB për transferimin e skedarëve"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB për transferimin e fotografive"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB për MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Tastierat e tjera"</string>
     <string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
     <string name="hardware" msgid="194658061510127999">"Shfaq tastierën virtuale"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Përzgjidh planin e tastierës"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Prek për të përzgjedhur tastierën."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bfc22e4..9f8c2c0 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Садржај је сакривен смерницама"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Лично"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Посао"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
@@ -1053,7 +1055,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"ово ће вам можда бити наплаћено"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Потврди"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB за пуњење"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB пуни овај уређај"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB снабдева енергијом прикључени уређај"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB за пренос датотека"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB за пренос слика"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
@@ -1071,8 +1074,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Друге тастатуре"</string>
     <string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Избор распореда тастатуре"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Додирните да бисте изабрали распоред тастатуре."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3f2a4a3..d3855f8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innehåll har dolts p.g.a. en policy"</string>
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personligt"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Arbetet"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"få tillgång till dina kontakter"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Plats"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"detta kan kosta pengar"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB för laddning"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Enheten laddas via USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"En ansluten enhet strömförsörjs via USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB för överföring av filer"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB för överföring av foton"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB för MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Andra tangentbord"</string>
     <string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
     <string name="hardware" msgid="194658061510127999">"Visa virtuellt tangentbord"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Välj en tangentbordslayout"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Välj en tangentbordslayout genom att trycka."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2e1a7a4..fd5c2c7 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -235,8 +235,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Maudhui yamefichwa kulingana na sera"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Binafsi"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Kazini"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
@@ -1047,7 +1049,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Hakuna vibali vinavyohitajika"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"huenda hii ikakugharimu pesa"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Sawa"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB kwa ajili ya kuchaji"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Unachaji kifaa hiki ukitumia USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB inachaji kifaa ulichounganisha"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB kwa ajili ya kuhamisha faili"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB kwa ajili ya kuhamisha picha"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB kwa ajili ya MIDI"</string>
@@ -1065,8 +1068,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Kibodi zingine"</string>
     <string name="show_ime" msgid="2506087537466597099">"Iweke kwenye skrini wakati kibodi inapotumika"</string>
     <string name="hardware" msgid="194658061510127999">"Onyesha kibodi pepe"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Teua mpangilio wa kibodi"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Gusa ili kuchagua mpangilio wa kibodi."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index b34caed..f92177a 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"கொள்கையின்படி உள்ளடக்கம் மறைக்கப்பட்டது"</string>
     <string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"தனிப்பட்ட"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"பணியிடம்"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"தொடர்புகள்"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"தொடர்புகளை அணுகும்"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"இருப்பிடம்"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"அனுமதிகள் தேவையில்லை"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"இதனால் நீங்கள் கட்டணம் செலுத்த வேண்டியிருக்கலாம்"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"சரி"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB, சார்ஜ் செய்வதற்கு மட்டும்"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"இந்தச் சாதனத்தை USB சார்ஜ் செய்கிறது"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"இணைத்துள்ள சாதனத்திற்கு USB சக்தி அளிக்கிறது"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB, கோப்புப் பரிமாற்றத்துக்கு மட்டும்"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB, படப் பரிமாற்றத்துக்கு மட்டும்"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB, MIDIக்கு மட்டும்"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"பிற விசைப்பலகைகள்"</string>
     <string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
     <string name="hardware" msgid="194658061510127999">"விர்ச்சுவல் விசைப்பலகையை காட்டு"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"விசைப்பலகைத் தளவமைப்பைத் தேர்ந்தெடுக்கவும்"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"விசைப்பலகைத் தளவமைப்பைத் தேர்ந்தெடுக்க தொடவும்."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 9beb1e1..9b5fc01 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"విధానం ద్వారా కంటెంట్‌లు దాచబడ్డాయి"</string>
     <string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"వ్యక్తిగతం"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"కార్యాలయం"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"పరిచయాలు"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"మీ పరిచయాలను ప్రాప్యత చేయడానికి"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"అనుమతులు అవసరం లేదు"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"దీనికి మీకు డబ్బు ఖర్చు కావచ్చు"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"సరే"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"ఛార్జింగ్ కోసం USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"ఈ పరికరం USB మోడ్‌లో ఛార్జ్ అవుతోంది"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"జోడించిన పరికరానికి USB ద్వారా పవర్ సరఫరా అవుతోంది"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"ఫైల్ బదిలీ కోసం USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"ఫోటో బదిలీ కోసం USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI కోసం USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"ఇతర కీబోర్డ్‌లు"</string>
     <string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్‌పై ఉంచుతుంది"</string>
     <string name="hardware" msgid="194658061510127999">"వర్చువల్ కీబోర్డ్‌ను చూపు"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"కీబోర్డ్ లేఅవుట్‌ను ఎంచుకోండి"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"కీబోర్డ్ లేఅవుట్‌ను ఎంచుకోవడానికి తాకండి."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్‌లు"</u></string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d0b6f43..ca401bc 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"มีการซ่อนเนื้อหาโดยนโยบาย"</string>
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"ที่ทำงาน"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"รายชื่อติดต่อ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"เข้าถึงรายชื่อติดต่อ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ตำแหน่ง"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"รายการนี้อาจมีการเรียกเก็บเงิน"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ตกลง"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB สำหรับการชาร์จ"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"กำลังชาร์จอุปกรณ์นี้ด้วย USB"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"กำลังจ่ายไฟให้อุปกรณ์ที่เชื่อมต่ออยู่ผ่าน USB"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB สำหรับการโอนไฟล์"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB สำหรับการโอนรูปภาพ"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB สำหรับ MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"แป้นพิมพ์อื่นๆ"</string>
     <string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
     <string name="hardware" msgid="194658061510127999">"แสดงแป้นพิมพ์เสมือน"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"เลือกรูปแบบแป้นพิมพ์"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"แตะเพื่อเลือกรูปแบบแป้นพิมพ์"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 698ae61..1a63a99 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Itinago ang mga content alinsunod sa patakaran"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Trabaho"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Mga Contact"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ina-access ang iyong mga contact"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Lokasyon"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Walang mga kinakailangang pahintulot"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"maaari itong magdulot ng gastos sa iyo"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB para sa pagcha-charge"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"China-charge sa USB ang device na ito"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB ang nagbibigay ng power sa nakakabit na device"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para sa paglipat ng file"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para sa paglipat ng larawan"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para sa MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Iba pang mga keyboard"</string>
     <string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
     <string name="hardware" msgid="194658061510127999">"Ipakita ang virtual keyboard"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Pumili ng layout ng keyboard"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Pindutin upang pumili ng layout ng keyboard."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 52c32e7..e4a44d2 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"İçerikler politika nedeniyle gizlendi"</string>
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Kişisel"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kişiler"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kişilerinize erişme"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Konum"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"bunun için sizden ücret alınabilir"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"Şarj için USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Bu cihaz USB\'den şarj oluyor"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, bağlı cihaza güç sağlıyor"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Dosya aktarımı için USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Fotoğraf aktarımı için USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI için USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Diğer klavyeler"</string>
     <string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
     <string name="hardware" msgid="194658061510127999">"Sanal klavyeyi göster"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Klavye düzeni seçin"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Bir klavye düzeni seçmek için dokunun."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8142aa0..a6020e8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -237,8 +237,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Вміст сховано згідно з правилом"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Особисті дані"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Службовий профіль"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"отримувати доступ до контактів"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Геодані"</string>
@@ -1061,7 +1063,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Дозвіл не потрібний"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"це платна послуга"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB для заряджання"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB-кабель, через який заряджається цей пристрій"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB-кабель, через який живиться під’єднаний пристрій"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перенесення файлів"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перенесення фотографій"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для режиму MIDI"</string>
@@ -1079,8 +1082,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Інші клавіатури"</string>
     <string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
     <string name="hardware" msgid="194658061510127999">"Показати віртуальну клавіатуру"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Виберіть розкладку клавіатури"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Торкніться, щоб вибрати розкладку клавіатури."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 41a1e82..b515c55 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"مواد پالیسی کے تحت مخفی ہے"</string>
     <string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏Android سسٹم"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"ذاتی"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"دفتر"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"رابطے"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"اپنے رابطوں تک رسائی حاصل کریں"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"مقام"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"کوئی اجازتیں درکار نہیں ہیں"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"اس میں آپ کا پیسہ خرچ ہو سکتا ہے"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ٹھیک ہے"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"‏چارجنگ کیلئے USB"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"‏USB اس آلے کو چارج کر رہی ہے"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏منسلکہ آلے کو USB پاور سپلائی کر رہی ہے"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏فائل کی منتقلی کیلئے USB"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"‏تصویر کی منتقلی کیلئے USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏MIDI کیلئے USB"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"دیگر کی بورڈز"</string>
     <string name="show_ime" msgid="2506087537466597099">"‏جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
     <string name="hardware" msgid="194658061510127999">"ورچوئل کی بورڈ دکھائیں"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"کی بورڈ کا خاکہ منتخب کریں"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"ایک کی بورڈ کا خاکہ منتخب کرنے کیلئے چھوئیں۔"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index e3b9e9a..6323f52 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Qoidaga muvofiq kontent yashirilgan"</string>
     <string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Shaxsiy"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Ish"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktlar"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktlarga kirish"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Hech qanday ruxsat talab qilinmaydi"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"buning uchun sizdan haq olinishi mumkin"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB orqali quvvatlash"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB orqali quvvatlash"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB orqali ulangan qurilma quvvatlanmoqda"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB orqali fayl o‘tkazish"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB orqali rasm o‘tkazish"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB orqali MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Boshqa klaviaturalar"</string>
     <string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
     <string name="hardware" msgid="194658061510127999">"Virtual klaviatura ko‘rsatilsin"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Tugmalar tartibini tanlash"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Tugmalar tartibini tanlash uchun bosing."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 76743f2..10516af 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Nội dung bị ẩn theo chính sách"</string>
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Cá nhân"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Cơ quan"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Danh bạ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"truy cập vào danh bạ của bạn"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vị trí"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Không yêu cầu quyền"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"bạn có thể mất tiền vì điều này"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB để sạc"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Sạc qua USB thiết bị này"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Nguồn cấp điện qua USB cho thiết bị được kết nối"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB để truyền tệp"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB để truyền ảnh"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB cho MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Bàn phím khác"</string>
     <string name="show_ime" msgid="2506087537466597099">"Tiếp tục sử dụng ứng dụng trên màn hình trong khi bàn phím thực đang hoạt động"</string>
     <string name="hardware" msgid="194658061510127999">"Hiển thị bàn phím ảo"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Chọn bố cục bàn phím"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Chạm để chọn bố cục bàn phím."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 3b0c075..f7bcaba 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"工作"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"访问您的通讯录"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"不需要任何权限"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"这可能会产生费用"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"确定"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"正在通过 USB 充电"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在通过 USB 为此设备充电"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在通过 USB 为连接的设备充电"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"正在通过 USB 传输文件"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"正在通过 USB 传输照片"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"正在通过 USB 连接到 MIDI 接口"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"其他键盘"</string>
     <string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
     <string name="hardware" msgid="194658061510127999">"显示虚拟键盘"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"选择键盘布局"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"触摸可选择键盘布局。"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
@@ -1224,7 +1229,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s - %2$s:%3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"内部共享的存储空间"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"内部共享存储空间"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD卡"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 卡"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"U 盘"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e15aaf2..15e9a5e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"已根據政策隱藏內容"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"公司"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通訊錄"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的通訊錄"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"不需授權"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"這可能需要付費"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB 充電"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在透過 USB 為此裝置充電"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在透過 USB 為已連接的裝置供電"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB 檔案傳輸"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB 相片傳輸"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"其他鍵盤"</string>
     <string name="show_ime" msgid="2506087537466597099">"在實體鍵盤處於連接狀態時保持顯示"</string>
     <string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"選取鍵盤配置"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"輕觸即可選取鍵盤配置。"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6e62d1c..a27f1b7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"內容已依據政策隱藏"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"公司"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"聯絡人"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"存取您的聯絡人"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"無須許可"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"這可能需要付費"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"正在透過 USB 充電"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"正在透過 USB 為這個裝置充電"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"正在透過 USB 為連接的裝置供電"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB 檔案傳輸"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB 相片傳輸"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"其他鍵盤"</string>
     <string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
     <string name="hardware" msgid="194658061510127999">"顯示虛擬鍵盤"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"選取鍵盤配置"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"輕觸即可選取鍵盤配置。"</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ddd486b..60be8fd 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -233,8 +233,10 @@
     <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Okuqukethwe kufihlwe inqubomgomo"</string>
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
-    <string name="user_owner_label" msgid="2804351898001038951">"Okomuntu siqu"</string>
-    <string name="managed_profile_label" msgid="6260850669674791528">"Umsebenzi"</string>
+    <!-- no translation found for user_owner_label (1119010402169916617) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (5289992269827577857) -->
+    <skip />
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Oxhumana nabo"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"finyelela koxhumana nabo"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Indawo"</string>
@@ -1045,7 +1047,8 @@
     <string name="no_permissions" msgid="7283357728219338112">"Ayikho imvume edingekayo"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"lokhu kungakudlela imali"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"KULUNGILE"</string>
-    <string name="usb_charging_notification_title" msgid="4004114449249406402">"I-USB yokushaja"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"I-USB ishaja le divayisi"</string>
+    <string name="usb_supplying_notification_title" msgid="5310642257296510271">"I-USB inikeza amandla kudivayisi enamathiselwe"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"I-USB yokudluliswa kwefayela"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"I-USB yokudluliswa kwesithombe"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"I-USB ye-MIDI"</string>
@@ -1063,8 +1066,10 @@
     <string name="configure_input_methods" msgid="5673193194563164021">"Amanye amakhibhodi"</string>
     <string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
     <string name="hardware" msgid="194658061510127999">"Bonisa ikhibhodi ebonakalayo"</string>
-    <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Khetha isendlalelo sekhibhodi"</string>
-    <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Thinta ukuze ukhethe isendlalelo sekhibhodi."</string>
+    <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4429001..0ed1f13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3528,6 +3528,13 @@
              This setting implies fastScrollEnabled. -->
         <attr name="fastScrollAlwaysVisible" format="boolean" />
     </declare-styleable>
+    <!-- @hide -->
+    <declare-styleable name="RecycleListView">
+        <!-- Bottom padding to use when no buttons are present. -->
+        <attr name="paddingBottomNoButtons" format="dimension" />
+        <!-- Top padding to use when no title is present. -->
+        <attr name="paddingTopNoTitle" format="dimension" />
+    </declare-styleable>
     <declare-styleable name="AbsSpinner">
         <!-- Reference to an array resource that will populate the Spinner.  For static content,
              this is simpler than populating the Spinner programmatically. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d1c0895..5b4364d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -225,6 +225,9 @@
             granted any application pre-installed on the system image (not just privileged
             apps). -->
         <flag name="preinstalled" value="0x400" />
+        <!-- Additional flag from base permission type: this permission can be automatically
+            granted to the setup wizard app -->
+        <flag name="setup" value="0x800" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 892b3d5..cae04ad 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -578,6 +578,9 @@
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
 
+    <!-- Fast brightness animation ramp rate -->
+    <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+
     <!-- Don't name config resources like this.  It should look like config_annoyDianne -->
     <bool name="config_annoy_dianne">true</bool>
 
@@ -2501,4 +2504,7 @@
     <!-- True if the device requires AppWidgetService even if it does not have
          the PackageManager.FEATURE_APP_WIDGETS feature -->
     <bool name="config_enableAppWidgetService">false</bool>
+
+    <!-- True if the device supports Sustained Performance Mode-->
+    <bool name="config_sustainedPerformanceModeSupported">false</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 71d9a1f..a21f276 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -450,6 +450,7 @@
     <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
 
     <item type="dimen" name="aerr_padding_list_top">15dp</item>
+    <item type="dimen" name="aerr_padding_list_bottom">8dp</item>
 
     <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
 
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index ad2b335d..00e48a0 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -117,13 +117,13 @@
 
     <dimen name="dialog_padding_material">24dp</dimen>
     <dimen name="dialog_padding_top_material">18dp</dimen>
+    <dimen name="dialog_title_divider_material">8dp</dimen>
+    <dimen name="dialog_list_padding_top_no_title">8dp</dimen>
+    <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen>
 
     <!-- Dialog padding minus control padding, used to fix alignment. -->
     <dimen name="select_dialog_padding_start_material">20dp</dimen>
 
-    <!-- Padding above and below selection dialog lists. -->
-    <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
-
     <dimen name="seekbar_track_background_height_material">2dp</dimen>
     <dimen name="seekbar_track_progress_height_material">2dp</dimen>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b878b00..b4f95dc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2945,8 +2945,6 @@
 
     <!-- Title of the pop-up dialog in which the user switches keyboard, also known as input method. -->
     <string name="select_input_method">Change keyboard</string>
-    <!-- Title of a button to open the settings to enable or disable other soft keyboards (also known as input methods) [CHAR LIMIT=30] -->
-    <string name="configure_input_methods">Other keyboards</string>
     <!-- Summary text of a toggle switch to enable/disable use of the IME while a physical
          keyboard is connected -->
     <string name="show_ime">Keep it on screen while physical keyboard is active</string>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 7dde5f8..341a0a4 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -17,27 +17,27 @@
     <style name="Animation.Micro"/>
 
     <style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
-        <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
-        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
-        <item name="activityOpenExitAnimation">@null</item>
+        <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="activityCloseEnterAnimation">@null</item>
         <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskOpenEnterAnimation">@anim/slide_in_micro</item>
-        <item name="taskOpenExitAnimation">@null</item>
+        <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="taskCloseEnterAnimation">@null</item>
         <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskToFrontEnterAnimation">@anim/slide_in_micro</item>
-        <item name="taskToFrontExitAnimation">@null</item>
+        <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="taskToBackEnterAnimation">@null</item>
         <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
         <item name="wallpaperOpenEnterAnimation">@null</item>
         <item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperCloseEnterAnimation">@anim/slide_in_micro</item>
-        <item name="wallpaperCloseExitAnimation">@null</item>
+        <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="wallpaperIntraOpenEnterAnimation">@null</item>
         <item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_micro</item>
-        <item name="wallpaperIntraCloseExitAnimation">@null</item>
+        <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
     </style>
 
     <style name="AlertDialog.Micro" parent="AlertDialog.Material.Light">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 694e934..1e10f86 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1766,6 +1766,7 @@
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
+  <java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
   <java-symbol type="layout" name="launch_warning" />
   <java-symbol type="layout" name="safe_mode" />
@@ -1810,7 +1811,6 @@
   <java-symbol type="string" name="config_wimaxServiceClassname" />
   <java-symbol type="string" name="config_wimaxServiceJarLocation" />
   <java-symbol type="string" name="config_wimaxStateTrackerClassname" />
-  <java-symbol type="string" name="configure_input_methods" />
   <java-symbol type="string" name="data_usage_3g_limit_snoozed_title" />
   <java-symbol type="string" name="data_usage_3g_limit_title" />
   <java-symbol type="string" name="data_usage_4g_limit_snoozed_title" />
@@ -2452,24 +2452,6 @@
   <java-symbol type="id" name="aerr_close" />
   <java-symbol type="id" name="aerr_mute" />
 
-  <!-- Framework-private Material.DayNight styles. -->
-  <java-symbol type="style" name="Theme.Material.DayNight" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DarkActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Alert" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
-  <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
-  <java-symbol type="style" name="Theme.Material.DayNight.Panel" />
-  <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
-
   <java-symbol type="string" name="status_bar_rotate" />
   <java-symbol type="string" name="status_bar_headset" />
   <java-symbol type="string" name="status_bar_data_saver" />
@@ -2557,4 +2539,9 @@
 
   <!-- WallpaperManager config -->
   <java-symbol type="string" name="config_wallpaperCropperPackage" />
+
+  <java-symbol type="id" name="textSpacerNoTitle" />
+  <java-symbol type="id" name="titleDividerNoCustom" />
+
+  <java-symbol type="bool" name="config_sustainedPerformanceModeSupported" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index a361eda..6611eb1 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1294,7 +1294,7 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
+    <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
 
@@ -1304,7 +1304,7 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.DayNight.NoActionBar">
+    <style name="Theme.Material.Settings.NoActionBar" parent="Theme.Material.Light.NoActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
 
@@ -1313,41 +1313,41 @@
         <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
     </style>
 
-    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
+    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
     <style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
 
-    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
+    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
     <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
 
-    <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar">
+    <style name="Theme.Material.Settings.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.DayNight.DialogWhenLarge.NoActionBar">
+    <style name="Theme.Material.Settings.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
+    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
+    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
 
-    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
+    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
     </style>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
deleted file mode 100644
index 4ecca6b..0000000
--- a/core/res/res/values/themes_material_daynight.xml
+++ /dev/null
@@ -1,117 +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.
--->
-
-<!--
-===============================================================
-                        PLEASE READ
-===============================================================
-
-The Material themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
-                        PLEASE READ
-===============================================================
- -->
-<resources>
-
-    <!-- Material theme (day/night vesion) for activities. -->
-    <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
-
-    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
-         with an inverse color profile. The dark action bar sharply stands out against
-         the light content (when applicable).  -->
-    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
-
-    <!-- Variant of Material.DayNight with no action bar.  -->
-    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen. This theme
-         sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
-
-    <!-- Variant of Material.DayNight that has no title bar and fills
-         the entire screen and extends into the display overscan region. This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
-
-    <!-- Variant of Material.DayNight that has no title bar and translucent
-         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
-         {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
-
-    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
-         to place your content. It makes the window floating, with a transparent
-         background, and turns off dimming behind the window. -->
-    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
-
-    <!-- Material theme (day/night vesion) for dialog windows and activities,
-         which is used by the {@link android.app.Dialog} class. This changes
-         the window to be floating (not fill the entire screen), and puts a
-         frame around its contents. You can set this theme on an activity if
-         you would like to make an activity that looks like a Dialog. -->
-    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
-    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
-         a regular dialog. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
-
-    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
-    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
-
-    <!-- Theme for a window that will be displayed either full-screen on
-         smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
-
-    <!-- Theme for a window with a dark action bar that will be displayed
-         either full-screen on smaller screens (small, normal) or as a dialog
-         on larger screens (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" parent="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
-
-    <!-- Theme for a window without an action bar that will be displayed either full-screen
-         on smaller screens (small, normal) or as a dialog on larger screens
-         (large, xlarge). -->
-    <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
-
-    <!-- Theme for a presentation window on a secondary display. -->
-    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
-
-    <!-- Material user theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class. -->
-    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
-    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
-
-    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
-    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
-
-</resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 76b5fe1..2e593a3 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -94,11 +94,27 @@
   <!-- This is the battery capacity in mAh (measured at nominal voltage) -->
   <item name="battery.capacity">1000</item>
 
-  <array name="wifi.batchedscan"> <!-- mA -->
-      <value>.0002</value> <!-- 1-8/hr -->
-      <value>.002</value>  <!-- 9-64/hr -->
-      <value>.02</value>   <!-- 65-512/hr -->
-      <value>.2</value>    <!-- 513-4,096/hr -->
-      <value>2</value>    <!-- 4097-/hr -->
+  <!-- Wifi related values. -->
+  <!-- Idle Receive current for wifi radio in mA. 0 by default-->
+  <item name="wifi.controller.idle">0</item>
+  <!-- Rx current for wifi radio in mA. 0 by default-->
+  <item name="wifi.controller.rx">0</item>
+  <!-- Tx current for wifi radio in mA. 0 by default-->
+  <item name="wifi.controller.tx">0</item>
+  <!-- Current at each of the wifi Tx levels in mA. The number of tx levels varies per device
+       and is available only of wifi chipsets which support the tx level reporting. Use
+        wifi.tx for other chipsets. none by default -->
+  <array name="wifi.controller.tx_levels"> <!-- mA -->
   </array>
+  <!-- Operating volatage for wifi radio in mV. 0 by default-->
+  <item name="wifi.controller.voltage">0</item>
+
+  <array name="wifi.batchedscan"> <!-- mA -->
+    <value>.0002</value> <!-- 1-8/hr -->
+    <value>.002</value>  <!-- 9-64/hr -->
+    <value>.02</value>   <!-- 65-512/hr -->
+    <value>.2</value>    <!-- 513-4,096/hr -->
+    <value>2</value>    <!-- 4097-/hr -->
+  </array>
+
 </device>
diff --git a/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
new file mode 100644
index 0000000..a6e433f
--- /dev/null
+++ b/core/tests/benchmarks/src/android/text/util/LinkifyBenchmark.java
@@ -0,0 +1,89 @@
+/*
+ * 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.util;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.util.Patterns;
+
+import java.util.regex.Pattern;
+
+public class LinkifyBenchmark {
+    private static final String MATCHING_STR = " http://user:pass@host.com:5432/path?k=v#f " +
+            "host.com:5432/path?k=v#f ";
+
+    private static final String NONMATCHING_STR = " Neque porro quisquam est qui dolorem ipsum " +
+            "quia dolor sit amet, consectetur, adipisci velit ";
+
+    // this pattern does not recognize strings without http scheme therefore is expected to be
+    // faster in MATCHING_STR case.
+    private static final Pattern BASIC_PATTERN = Pattern.compile(
+            "(?:\\b|$|^)http://[a-zA-Z0-9:\\.@\\?=#/]+(?:\\b|$|^)");
+
+    @Param({"1", "4", "16", "64", "256"})
+    private String mParamCopyAmount;
+
+    @Param({MATCHING_STR, NONMATCHING_STR})
+    private String mParamBasicText;
+
+    private Spannable mTestSpannable;
+
+    @BeforeExperiment
+    protected void setUp() throws Exception {
+        int copyAmount = Integer.valueOf(mParamCopyAmount);
+        StringBuilder strBuilder = new StringBuilder();
+        for (int i = 0; i < copyAmount; i++) {
+            strBuilder.append(mParamBasicText);
+        }
+        mTestSpannable = new SpannableString(strBuilder.toString());
+    }
+
+    @AfterExperiment
+    protected void tearDown() {
+        mTestSpannable = null;
+    }
+
+    @Benchmark
+    public void timeNewRegEx(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            Linkify.addLinks(mTestSpannable, Patterns.AUTOLINK_WEB_URL, "http://",
+                    new String[]{"http://", "https://", "rtsp://"}, null, null);
+        }
+    }
+
+    @Benchmark
+    public void timeOldRegEx(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            Linkify.addLinks(mTestSpannable, Patterns.WEB_URL, "http://",
+                    new String[]{"http://", "https://", "rtsp://"}, null, null);
+        }
+    }
+
+    @Benchmark
+    public void timeBasicRegEx(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            Linkify.addLinks(mTestSpannable, BASIC_PATTERN, "http://",
+                    new String[]{"http://", "https://", "rtsp://"}, null, null);
+        }
+    }
+
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index b780778..b7926cf 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1093,7 +1093,12 @@
             </intent-filter>
         </activity>
 
-
+        <activity android:name="android.view.ViewCaptureTestActivity" android:label="ViewCaptureTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
 
         <!-- Activity-level metadata -->
         <meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
@@ -1251,6 +1256,15 @@
         <service android:name="android.os.BinderThreadPriorityService"
                 android:process=":BinderThreadPriorityService" />
 
+        <!-- Used by ApplyOverrideConfigurationTest -->
+        <activity android:name="android.app.activity.ApplyOverrideConfigurationActivity"
+                  android:configChanges="orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <!-- Application components used for search manager tests -->
 
         <activity android:name="android.app.activity.SearchableActivity"
diff --git a/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png b/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png
new file mode 100644
index 0000000..52092c4
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/view_capture_test_no_children_golden.png
Binary files differ
diff --git a/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png b/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png
new file mode 100644
index 0000000..3bcbd9a
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/view_capture_test_with_children_golden.png
Binary files differ
diff --git a/core/tests/coretests/res/layout/view_capture_snapshot.xml b/core/tests/coretests/res/layout/view_capture_snapshot.xml
new file mode 100644
index 0000000..0b589a4
--- /dev/null
+++ b/core/tests/coretests/res/layout/view_capture_snapshot.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout android:id="@+id/capture"
+        android:background="#00f"
+        android:orientation="vertical"
+        android:layout_width="100px"
+        android:layout_height="100px">
+
+        <View android:id="@+id/child1"
+            android:background="#f00"
+            android:layout_width="match_parent"
+            android:layout_height="25px"/>
+
+        <View android:id="@+id/child2"
+            android:background="#fff"
+            android:layout_width="match_parent"
+            android:layout_height="25px"
+            android:visibility="invisible"/>
+
+        <View android:id="@+id/child3"
+            android:background="#ff0"
+            android:layout_width="match_parent"
+            android:layout_height="25px"
+            android:visibility="gone"/>
+
+        <View android:id="@+id/child4"
+            android:background="#0ff"
+            android:layout_width="match_parent"
+            android:layout_height="25px" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index 4a53852..d1a5d28 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -284,20 +284,30 @@
         Uri uri = getServerUri(DEFAULT_FILENAME);
         enqueueResponse(buildResponse(HTTP_PARTIAL_CONTENT));
 
-        doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
+        doErrorTest(uri, DownloadManager.ERROR_CANNOT_RESUME);
     }
 
     /**
      * Tests the download failure error from an unhandled HTTP status code
      */
     @LargeTest
-    public void testErrorHttpDataError_invalidRedirect() throws Exception {
+    public void testRelativeRedirect() throws Exception {
         Uri uri = getServerUri(DEFAULT_FILENAME);
         final MockResponse resp = buildResponse(HTTP_REDIRECT);
-        resp.setHeader("Location", "://blah.blah.blah.com");
+        resp.setHeader("Location", ":" + uri.getSchemeSpecificPart());
         enqueueResponse(resp);
 
-        doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR);
+        byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
+        enqueueResponse(buildResponse(HTTP_OK, blobData));
+
+        Request request = new Request(uri);
+        request.setTitle(DEFAULT_FILENAME);
+
+        long dlRequest = mDownloadManager.enqueue(request);
+        waitForDownloadOrTimeout(dlRequest);
+
+        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
+        assertEquals(1, mReceiver.numDownloadsCompleted());
     }
 
     /**
diff --git a/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java
new file mode 100644
index 0000000..3df522d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.app.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+
+public class ApplyOverrideConfigurationActivity extends Activity {
+
+    @Override
+    protected void attachBaseContext(Context newBase) {
+        super.attachBaseContext(newBase);
+
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.smallestScreenWidthDp = ApplyOverrideConfigurationTest.OVERRIDE_WIDTH;
+        applyOverrideConfiguration(overrideConfig);
+    }
+}
diff --git a/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java
new file mode 100644
index 0000000..15ed77e
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ApplyOverrideConfigurationTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.app.activity;
+
+import android.app.UiAutomation;
+import android.content.res.Configuration;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.ActivityInstrumentationTestCase2;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ApplyOverrideConfigurationTest extends
+        ActivityInstrumentationTestCase2<ApplyOverrideConfigurationActivity> {
+
+    public static final int OVERRIDE_WIDTH = 9999;
+
+    public ApplyOverrideConfigurationTest() {
+        super(ApplyOverrideConfigurationActivity.class);
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+    }
+
+    @Test
+    public void testConfigurationIsOverriden() throws Exception {
+        Configuration config = getActivity().getResources().getConfiguration();
+        assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
+
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
+
+        config = getActivity().getResources().getConfiguration();
+        assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+        super.tearDown();
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index 3cadbf6..d4bb0f3 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -18,7 +18,7 @@
 import android.annotation.NonNull;
 import android.app.ResourcesManager;
 import android.os.Binder;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
 import android.util.DisplayMetrics;
 import android.util.LocaleList;
 import android.util.TypedValue;
@@ -58,7 +58,7 @@
             }
 
             @Override
-            protected DisplayMetrics getDisplayMetricsLocked(int displayId) {
+            protected DisplayMetrics getDisplayMetrics(int displayId) {
                 return mDisplayMetrics;
             }
         };
@@ -173,25 +173,12 @@
 
         // The implementations should be the same.
         assertSame(resources1.getImpl(), resources2.getImpl());
-
-        final Configuration overrideConfig = new Configuration();
-        overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
-        Resources resources3 = mResourcesManager.getResources(
-                activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
-                overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
-
-        // Since we requested new resources for activity2, the resource should be the same
-        // as the one returned before for activity2.
-        assertSame(resources2, resources3);
-
-        // But the implementation has changed.
-        assertNotSame(resources1.getImpl(), resources2.getImpl());
     }
 
     @SmallTest
     public void testThemesGetUpdatedWithNewImpl() {
         Binder activity1 = new Binder();
-        Resources resources1 = mResourcesManager.getResources(
+        Resources resources1 = mResourcesManager.createBaseActivityResources(
                 activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
         assertNotNull(resources1);
@@ -207,16 +194,59 @@
 
         final Configuration overrideConfig = new Configuration();
         overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
-        Resources resources2 = mResourcesManager.getResources(
-                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
-                overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
-        assertNotNull(resources2);
-        assertSame(resources1, resources2);
-        assertSame(resources2, theme.getResources());
+        mResourcesManager.updateResourcesForActivity(activity1, overrideConfig);
+        assertSame(resources1, theme.getResources());
 
         // Make sure we can still access the data.
         assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
         assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
         assertTrue(value.data != 0);
     }
+
+    @SmallTest
+    public void testMultipleResourcesForOneActivityGetUpdatedWhenActivityBaseUpdates() {
+        Binder activity1 = new Binder();
+
+        // Create a Resources for the Activity.
+        Configuration config1 = new Configuration();
+        config1.densityDpi = 280;
+        Resources resources1 = mResourcesManager.createBaseActivityResources(
+                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources1);
+
+        // Create a Resources based on the Activity.
+        Configuration config2 = new Configuration();
+        config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+        Resources resources2 = mResourcesManager.getResources(
+                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        assertNotNull(resources2);
+
+        assertNotSame(resources1, resources2);
+        assertNotSame(resources1.getImpl(), resources2.getImpl());
+
+        final Configuration expectedConfig1 = new Configuration();
+        expectedConfig1.setLocales(LocaleList.getAdjustedDefault());
+        expectedConfig1.densityDpi = 280;
+        assertEquals(expectedConfig1, resources1.getConfiguration());
+
+        // resources2 should be based on the Activity's override config, so the density should
+        // be the same as resources1.
+        final Configuration expectedConfig2 = new Configuration();
+        expectedConfig2.setLocales(LocaleList.getAdjustedDefault());
+        expectedConfig2.densityDpi = 280;
+        expectedConfig2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
+        assertEquals(expectedConfig2, resources2.getConfiguration());
+
+        // Now update the Activity base override, and both resources should update.
+        config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mResourcesManager.updateResourcesForActivity(activity1, config1);
+
+        expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        assertEquals(expectedConfig1, resources1.getConfiguration());
+
+        expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        assertEquals(expectedConfig2, resources2.getConfiguration());
+    }
 }
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index ec8cd71..43a61e3 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -31,6 +31,7 @@
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
 import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
 
 import android.print.mockservice.MockPrintService;
 import android.print.mockservice.PrintServiceCallbacks;
@@ -181,6 +182,17 @@
                 new Handler(Looper.getMainLooper()));
     }
 
+    /**
+     * Create a IPrintServiceRecommendationsChangeListener object.
+     *
+     * @return the object
+     * @throws Exception if the object could not be created.
+     */
+    private IRecommendationsChangeListener
+    createMockIPrintServiceRecommendationsChangeListener() throws Exception {
+        return new PrintManager.PrintServiceRecommendationsChangeListenerWrapper(null,
+                new Handler(Looper.getMainLooper()));
+    }
 
     /**
      * Create a IPrinterDiscoveryObserver object.
@@ -559,6 +571,61 @@
     }
 
     /**
+     * test IPrintManager.addPrintServiceRecommendationsChangeListener
+     */
+    @MediumTest
+    public void testAddPrintServiceRecommendationsChangeListener() throws Exception {
+        final IRecommendationsChangeListener listener =
+                createMockIPrintServiceRecommendationsChangeListener();
+
+        mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.removePrintServicesChangeListener
+     */
+    @MediumTest
+    public void testRemovePrintServiceRecommendationsChangeListener() throws Exception {
+        final IRecommendationsChangeListener listener =
+                createMockIPrintServiceRecommendationsChangeListener();
+
+        mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+        mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
+
+        // Removing unknown listeners is a no-op
+        mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
+
+        mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getPrintServiceRecommendations
+     */
+    @MediumTest
+    public void testGetPrintServiceRecommendations() throws Exception {
+        mIPrintManager.getPrintServiceRecommendations(mUserId);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
      * test IPrintManager.createPrinterDiscoverySession
      */
     @MediumTest
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTest.java b/core/tests/coretests/src/android/view/ViewCaptureTest.java
new file mode 100644
index 0000000..15cfe23
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewCaptureTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseIntArray;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class ViewCaptureTest {
+
+    private static final SparseIntArray EXPECTED_CHILDREN_VISIBILITY = new SparseIntArray();
+    static {
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child1, View.VISIBLE);
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child2, View.INVISIBLE);
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child3, View.GONE);
+        EXPECTED_CHILDREN_VISIBILITY.append(R.id.child4, View.VISIBLE);
+    }
+
+    @Rule
+    public ActivityTestRule<ViewCaptureTestActivity> mActivityRule = new ActivityTestRule<>(
+            ViewCaptureTestActivity.class);
+
+    private Activity mActivity;
+    private ViewGroup mViewToCapture;
+
+    @Before
+    public void setUp() throws Exception {
+        mActivity = mActivityRule.getActivity();
+        mViewToCapture = (ViewGroup) mActivity.findViewById(R.id.capture);
+    }
+
+    @Test
+    @SmallTest
+    public void testCreateSnapshot() {
+        assertChildrenVisibility();
+        testCreateSnapshot(true, R.drawable.view_capture_test_no_children_golden);
+        assertChildrenVisibility();
+        testCreateSnapshot(false, R.drawable.view_capture_test_with_children_golden);
+        assertChildrenVisibility();
+    }
+
+    private void testCreateSnapshot(boolean skipChildren, int goldenResId) {
+        Bitmap result = mViewToCapture.createSnapshot(Bitmap.Config.ARGB_8888, 0, skipChildren);
+        Bitmap golden = BitmapFactory.decodeResource(mActivity.getResources(), goldenResId);
+        assertTrue(golden.sameAs(result));
+    }
+
+    private void assertChildrenVisibility() {
+        for (int i = 0; i < EXPECTED_CHILDREN_VISIBILITY.size(); i++) {
+            int id = EXPECTED_CHILDREN_VISIBILITY.keyAt(i);
+            View child = mViewToCapture.findViewById(id);
+            Assert.assertEquals(EXPECTED_CHILDREN_VISIBILITY.get(id), child.getVisibility());
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
new file mode 100644
index 0000000..20e3eb5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+public class ViewCaptureTestActivity extends Activity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.view_capture_snapshot);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index f779d6c..ecf88f1 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -675,4 +675,26 @@
         assertFloatingToolbarContainsItem(
                 getActivity().getString(com.android.internal.R.string.copy));
     }
+
+    @SmallTest
+    public void testTransientState() throws Exception {
+        final String text = "abc def";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        assertFalse(textView.hasTransientState());
+
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
+        // hasTransientState should return true when user generated selection is active.
+        assertTrue(textView.hasTransientState());
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
+        // hasTransientState should return false as the selection has been cleared.
+        assertFalse(textView.hasTransientState());
+        textView.post(
+                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
+        getInstrumentation().waitForIdleSync();
+        // hasTransientState should return false when selection is created by API.
+        assertFalse(textView.hasTransientState());
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index b8ea2de..bec4180 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -21,7 +21,6 @@
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
 import android.support.test.espresso.action.MotionEvents;
 import android.support.test.espresso.action.MotionEvents.DownResultHolder;
 import android.support.test.espresso.action.Press;
@@ -34,7 +33,7 @@
  * ViewAction for performing an click on View by a mouse.
  */
 public final class MouseClickAction implements ViewAction {
-    private final GeneralClickAction mGeneralClickAction;
+    private final ViewClickAction mViewClickAction;
     @MouseUiController.MouseButton
     private final int mButton;
 
@@ -100,30 +99,22 @@
      */
     public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
             @MouseUiController.MouseButton int button) {
-        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
+        mViewClickAction = new ViewClickAction(tapper, coordinatesProvider, Press.PINPOINT);
         mButton = button;
     }
 
     @Override
     public Matcher<View> getConstraints() {
-        return mGeneralClickAction.getConstraints();
+        return mViewClickAction.getConstraints();
     }
 
     @Override
     public String getDescription() {
-        return mGeneralClickAction.getDescription();
+        return mViewClickAction.getDescription();
     }
 
     @Override
     public void perform(UiController uiController, View view) {
-        mGeneralClickAction.perform(new MouseUiController(uiController, mButton), view);
-        long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
-        if (0 < doubleTapTimeout) {
-            // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
-            // detected as a triple click. e.g. 2 double clicks are detected as a triple click and
-            // a single click because espresso isn't aware of triple click detection logic, which
-            // is TextView specific gesture.
-            uiController.loopMainThreadForAtLeast(doubleTapTimeout);
-        }
+        mViewClickAction.perform(new MouseUiController(uiController, mButton), view);
     }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 4cecb65..335d021 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -17,15 +17,10 @@
 package android.widget.espresso;
 
 import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
-
-import org.hamcrest.core.Is;
-import org.hamcrest.core.IsInstanceOf;
-
 import android.graphics.Rect;
 import android.support.test.espresso.PerformException;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
 import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Tap;
 import android.support.test.espresso.util.HumanReadables;
@@ -55,7 +50,7 @@
      */
     public static ViewAction clickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new GeneralClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
+                new ViewClickAction(Tap.SINGLE, new TextCoordinates(index), Press.FINGER));
     }
 
     /**
@@ -101,7 +96,7 @@
      */
     public static ViewAction doubleClickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
+                new ViewClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
     }
 
     /**
@@ -131,7 +126,7 @@
      */
     public static ViewAction longPressOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
+                new ViewClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
     }
 
     /**
diff --git a/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
new file mode 100644
index 0000000..8bce1b0
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/ViewClickAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import org.hamcrest.Matcher;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Tapper;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+public final class ViewClickAction implements ViewAction {
+    private final GeneralClickAction mGeneralClickAction;
+
+    public ViewClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
+            PrecisionDescriber precisionDescriber) {
+        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
+                precisionDescriber);
+    }
+
+    @Override
+    public Matcher<View> getConstraints() {
+        return mGeneralClickAction.getConstraints();
+    }
+
+    @Override
+    public String getDescription() {
+        return mGeneralClickAction.getDescription();
+    }
+
+    @Override
+    public void perform(UiController uiController, View view) {
+        mGeneralClickAction.perform(uiController, view);
+        long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+        if (0 < doubleTapTimeout) {
+            // Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
+            // detected as a double click or triple click. e.g. 2 double clicks on TextView are
+            // detected as a triple click and a single click because espresso isn't aware of
+            // TextView specific gestures.
+            uiController.loopMainThreadForAtLeast(doubleTapTimeout);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 7519627..2a24881 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -22,7 +22,6 @@
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index fd28f64..e3639ec 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -101,8 +101,13 @@
 checkbuild: fontchain_lint
 
 FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+CHECK_EMOJI := false
+else
+CHECK_EMOJI := true
+endif
 
 .PHONY: fontchain_lint
 fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml
 	PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
-	python $(FONTCHAIN_LINTER) $(TARGET_OUT) external/unicode
+	python $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
diff --git a/docs/docs-redirect-index.html b/docs/docs-redirect-index.html
index dc0bc72..ea5f186 100644
--- a/docs/docs-redirect-index.html
+++ b/docs/docs-redirect-index.html
@@ -1,8 +1,8 @@
-<html>

-<head>

-<meta http-equiv="refresh" content="0;url=framework/index.html">

-</head>

-<body>

-<a href="framework/index.html">click here if you are not redirected</a>

-</body>

-</html>

+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=framework/index.html">
+</head>
+<body>
+<a href="framework/index.html">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/docs-redirect.html b/docs/docs-redirect.html
index 4e0743e..d83564c 100644
--- a/docs/docs-redirect.html
+++ b/docs/docs-redirect.html
@@ -1,8 +1,8 @@
-<html>

-<head>

-<meta http-equiv="refresh" content="0;url=docs/offline.html">

-</head>

-<body>

-<a href="docs/offline.html">click here if you are not redirected</a>

-</body>

-</html>

+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=docs/offline.html">
+</head>
+<body>
+<a href="docs/offline.html">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/docs-samples-redirect.html b/docs/docs-samples-redirect.html
index 4e549e6..abefe6c 100644
--- a/docs/docs-samples-redirect.html
+++ b/docs/docs-samples-redirect.html
@@ -1,8 +1,8 @@
-<html>

-<head>

-<meta http-equiv="refresh" content="0;url=../../samples/">

-</head>

-<body>

-<a href="../../samples/">click here if you are not redirected</a>

-</body>

-</html>

+<html>
+<head>
+<meta http-equiv="refresh" content="0;url=../../samples/">
+</head>
+<body>
+<a href="../../samples/">click here if you are not redirected</a>
+</body>
+</html>
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 0a96a15..e60ca9f 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -1,484 +1,484 @@
-page.title=Localizing with Resources

-parent.title=Application Resources

-page.tags="localizing","localization","resources", "formats", "l10n"

-parent.link=index.html

-@jd:body

-

-<div id="qv-wrapper">

-    <div id="qv">

-

-<h2>Quickview</h2>

-

-<ul>

-  <li>Use resource sets to create a localized app.</li>

-  <li>Android loads the correct resource set for the user's language and locale.</li>

-  <li>If localized resources are not available, Android loads your default resources.</li>

-</ul>

-

-<h2>In this document</h2>

-<ol>

-  <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>

-<li><a href="#using-framework">Using Resources for Localization</a></li>

-<li><a href="#strategies">Localization Tips</a></li>

-<li><a href="#testing">Testing Localized Applications</a></li>

-</ol>

-

-<h2>See also</h2>

-  <ol>

-    <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>

-    <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>

-    <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>

-    <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>

-</ol>

-</div>

-</div>

-

-<p>Android will run on many  devices in many  regions. To reach the most users,

-your application should handle text, audio files, numbers, currency, and

-graphics in ways appropriate to the locales where your application will be used.

-</p>

-

-<p>This document describes best practices for localizing Android

-applications. The principles apply whether you are developing your application  

-using ADT with Eclipse, Ant-based tools, or any other IDE. </p>

-

-<p>You should already have a working knowledge of Java and be  familiar with

-Android resource loading, the declaration of user interface elements in XML,

-development considerations such as Activity lifecycle, and general principles of

-internationalization and localization. </p>

-

-<p>It is good practice to use the Android resource framework to separate the

-localized aspects of your application as much as possible from the core Java

-functionality:</p>

-

-<ul>

-  <li>You can put most or all of the <em>contents</em> of your application's

-user interface into resource files, as described in this document and in <a

-href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>

-  <li>The <em>behavior</em> of the user interface, on the other hand, is driven

-by your Java code. 

-    For example, if users input data that needs to be formatted or sorted

-differently depending on locale, then you would use Java to handle the data

-programmatically. This document does not cover how to  localize your Java code.

-</li>

-</ul>

-

-<p>For a short guide to localizing strings in your app, see the training lesson, <a

-href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>

-

-

-<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>

-

-<p>Resources are text strings, layouts, sounds, graphics, and any other static

-data that your  Android application  needs. An application can include multiple

-sets of resources, each customized for a different device configuration. When a

-user runs the application,  Android    automatically selects and loads the 

-resources that best match the device.</p>

-

-<p>(This document focuses on localization and locale. For a complete description

-of resource-switching and all the types of configurations that you can

-specify &#8212; screen orientation, touchscreen type, and so on &#8212; see <a

-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing

-Alternative Resources</a>.)</p>

-

-<table border="0" cellspacing="0" cellpadding="0">

-  <tr border="0">

-    <td width="180" style="border: 0pt none ;"><p class="special-note">

-    <strong>When you write your application:</strong>

-    <br><br>

-    You create a set of default resources, plus alternatives to be used in

-    different locales.</p></td>

-    <td style="border: 0pt none; padding:0">

-    <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow" 

-    width="51" height="17"></p></td>

-    <td width="180" style="border: 0pt none ;"><p class="special-note">

-    <strong>When a user runs your application:</strong>

-    <br><br>The Android system selects which resources to load, based on the

-    device's locale.</p></td>

-  </tr>

-</table>

-

-<p>When you write your application, you create default and alternative resources

-for your application to use. To create  resources, you place files within

-specially named subdirectories of the project's <code>res/</code> directory.

-</p>

-

-

-

-<h3 id="defaults-r-important">Why Default Resources Are Important</h3>

-

-<p>Whenever the application runs in a locale for which you have not provided

-locale-specific text,  Android will load the default strings from

-<code>res/values/strings.xml</code>. If this default  file is absent, or if it 

-is missing a string that your application needs, then your application will not run 

-and will show an error. 

-The example below illustrates what can happen when the default text file is incomplete. </p>

-

-<p><em>Example:</em>

-<p>An application's Java code refers to just two strings, <code>text_a</code> and 

-	<code>text_b</code>. This application includes a localized resource file 

-	(<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and 

-	<code>text_b</code> in English. This application also includes a default 

-	resource file (<code>res/values/strings.xml</code>) that includes a

-definition for <code>text_a</code>, but not for <code>text_b</code>:

-<ul>

-  <li>This application might compile without a problem. An IDE such as Eclipse 

-  	will not highlight any errors if a resource is missing.</li>

-  <li>When this application is launched on a device with locale set to English, 

-  	the application  might run without a problem, because 

-  	<code>res/values-en/strings.xml</code> contains both of the needed text 

-  	strings.</li>

-  <li>However, <strong>the user  will see an error message and a Force Close 

-  	button</strong> when this application is launched on a device set to a 

-  	language other than English. The application will not load.</li>

-</ul>

-

-

-<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code> 

-	file exists and that it defines every needed string. The situation applies to 

-	all types of resources, not just strings: You 

-	need to create a  set of default resource files containing all 

-	the resources that your application calls upon &#8212; layouts, drawables, 

-	animations, etc. For information about testing, see <a href="#test-for-default">

-	Testing for Default Resources</a>.</p>

-

-<h2 id="using-framework">Using Resources for Localization</h2>

-

-<h3 id="creating-defaults">How to Create Default Resources</h3>

-

-<p>Put the application's default text in

-a file with the following location and name:</p>

-<p><code>&nbsp;&nbsp;&nbsp;&nbsp;res/values/strings.xml</code> (required directory)</p>

-

-<p>The text strings in <code>res/values/strings.xml</code> should  use the

-default language, which is the language that you expect most of your application's users to

-speak.  </p>

-

-<p>The default resource set must also include any default drawables and layouts, 

-	and can include other types of resources such as animations. 

-<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/drawable/</code>(required directory holding at least

-  one graphic file, for the application's icon on Google Play)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/layout/</code> (required directory holding an XML

-  file that defines the default layout)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/anim/</code> (required if you have any 

-  <code>res/anim-<em>&lt;qualifiers&gt;</em></code> folders)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/xml/</code> (required if you have any 

-  <code>res/xml-<em>&lt;qualifiers&gt;</em></code> folders)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/raw/</code> (required if you have any 

-  <code>res/raw-<em>&lt;qualifiers&gt;</em></code> folders)

-</p>

-

-<p class="note"><strong>Tip:</strong> In your code, examine each reference to 

-	an Android resource. Make sure that a default resource is defined for each

-	one. Also make sure that the default string file is complete: A <em>

-	localized</em> string file can contain a subset of the strings, but the 

-	<em>default</em> string file must contain them all. 

-</p>

-

-<h3 id="creating-alternatives">How to Create Alternative Resources</h3>

-

-<p>A large part of localizing an application is providing alternative text for

-different languages. In some cases you will also provide alternative graphics,

-sounds, layouts, and other locale-specific resources. </p>

-

-<p>An application can specify many <code>res/<em>&lt;qualifiers&gt;</em>/</code>

-directories, each with different qualifiers. To create an alternative resource for

-a different locale, you use a qualifier that specifies a language or a 

-language-region combination. (The name of a resource directory must conform 

-to the naming scheme described in 

-<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing

-Alternative Resources</a>,

-or else it will not compile.)</p>

-

-<p><em>Example:</em></p>

-

-<p>Suppose that your application's default language is English. Suppose also

-that you want to localize all the text in your application to French, and most

-of the text in your application (everything except the application's title) to

-Japanese. In this case, you could create three alternative <code>strings.xml</code>

-files, each stored in a locale-specific resource directory:</p>

-

-<ol>

-  <li><code>res/values/strings.xml</code><br>

-    Contains  English text for all  the strings that the application uses,

-including text for a string named <code>title</code>.</li>

-  <li><code>res/values-fr/strings.xml</code><br>

-    Contain French text for all  the strings, including <code>title</code>.</li>

-  <li><code>res/values-ja/strings.xml</code><br>

-    Contain Japanese text for all  the strings <em>except</em>

-<code>title</code>.<br>

-  <code></code></li>

-</ol>

-

-<p>If your Java code refers to <code>R.string.title</code>,  here is what will

-happen at runtime:</p>

-

-<ul>

-  <li>If the device is set to any language other than French, Android will load

-<code>title</code> from the <code>res/values/strings.xml</code> file.</li>

-  <li>If the device is set to French, Android will load <code>title</code> from

-the <code>res/values-fr/strings.xml</code> file.</li>

-</ul>

-

-<p>Notice that if the device is set to Japanese, Android will look for

-<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But

-because no such string is included in that file, Android will fall back to the

-default, and will load  <code>title</code> in English from the

-<code>res/values/strings.xml</code> file.  </p>

-

-<h3 id="resource-precedence">Which Resources Take Precedence?</h3>

-

-<p> If multiple resource files match a device's configuration, Android follows a

-set of rules in deciding which file to use. Among the qualifiers that can be

-specified in a resource directory name, <strong>locale almost always takes

-precedence</strong>. </p>

-<p><em>Example:</em></p>

-

-<p>Assume that an application  includes a default set of graphics and two other

-sets of graphics, each optimized for a different device setup:</p>

-

-<ul>

-  <li><code>res/drawable/</code><br>

-    Contains

-  default graphics.</li>

-  <li><code>res/drawable-small-land-stylus/</code><br>

-  Contains  graphics optimized for use with a device that expects input from a 

-  stylus and has a QVGA low-density screen in landscape orientation.</li>

-  <li><code>res/drawable-ja/</code> <br>

-  Contains  graphics optimized for use with Japanese.</li>

-</ul>

-

-<p>If the application runs on a device that is configured to use Japanese,

-Android will load graphics from  <code>res/drawable-ja/</code>, even if the

-device happens to be one that expects input from a stylus and has a QVGA 

-low-density screen in landscape orientation.</p>

-

-<p class="note"><strong>Exception:</strong> The only qualifiers that take

-precedence over locale in the selection process are MCC and MNC (mobile country

-code and mobile network code). </p>

-

-<p><em>Example:</em></p>

-

-<p>Assume that you have the following situation:</p>

-

-<ul>

-  <li>The application code calls for <code>R.string.text_a</code></li>

-  <li>Two relevant resource files are available:

-    <ul>

-      <li><code>res/values-mcc404/strings.xml</code>, which includes

-<code>text_a</code> in the application's default language, in this case

-English.</li>

-      <li><code>res/values-hi/strings.xml</code>, which includes

-<code>text_a</code> in Hindi.</li>

-    </ul>

-  </li>

-  <li>The application is running on a device that has the following

-configuration:

-    <ul>

-      <li>The SIM card is connected to a mobile network in India (MCC 404).</li>

-      <li>The language is set to Hindi (<code>hi</code>).</li>

-    </ul>

-  </li>

-</ul>

-

-<p>Android will load <code>text_a</code> from

-<code>res/values-mcc404/strings.xml</code> (in English), even if the device is

-configured for Hindi. That is because in the resource-selection process, Android

-will prefer an MCC match over a language match. </p>

-

-<p>The selection process is not always as straightforward as these examples

-suggest. Please read  <a

-href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds

-the Best-matching Resource</a> for a more nuanced description of the

-process. All the qualifiers are described and listed in order of

-precedence in <a

-href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing

-Alternative Resources</a>.</p>

-

-<h3 id="referring-to-resources">Referring to Resources in Java</h3>

-

-<p>In your application's Java code, you refer to  resources using the syntax

-<code>R.<em>resource_type</em>.<em>resource_name</em></code> or

-<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>

-For more about this, see <a

-href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>

-

-<h2 id="checklist">Localization Checklist</h2>

-

-<p>For a complete overview of the process of localizing and distributing an Android application,

-see the <a href="{@docRoot}distribute/tools/localization-checklist.html">Localization

-Checklist</a> document.</p>

-

-<h2 id="strategies">Localization Tips</h2>

-

-<h4 id="failing2">Design your application  to work in any locale</h4>

-

-<p>You cannot assume anything about the device on which a user will

-run your application. The device might have hardware that you were not

-anticipating, or it might be set to a locale that you did not plan for or that 

-you cannot test. Design your application so that it will function normally or fail gracefully no 

-matter what device it runs on.</p>

-

-<p class="note"><strong>Important:</strong> Make sure that your application

-includes a full set of default resources.</p> <p>Make sure to include

-<code>res/drawable/</code> and a <code>res/values/</code> folders (without any

-additional modifiers in the folder names) that contain all the images and text

-that your application will need. </p>

-

-<p>If an application is missing even one default resource, it will not run on a 

-	device that is set to an unsupported locale. For example, the 

-	<code>res/values/strings.xml</code> default file might lack one string that 

-	the application needs: When the application runs in an unsupported locale and 

-	attempts to load <code>res/values/strings.xml</code>, the user will see an 

-	error message and a Force Close button. An IDE such as Eclipse will not 

-	highlight this kind of error, and you will not see the problem when you 

-	test the application on a device or emulator that is set to a supported locale.</p>

-

-<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>

-

-<h4>Design a flexible layout</h4>

-

-<p> If you need to rearrange your layout to fit a certain language (for example

-German with its long words), you can create an alternative layout for that

-language (for example <code>res/layout-de/main.xml</code>). However, doing this

-can make your application harder to maintain.  It is better to create a single

-layout that is more flexible.</p>

-

-<p>Another typical situation is a language that requires something different in

-its layout. For example, you might have a contact form that should include  two

-name fields when the application runs in Japanese, but three name fields when

-the application  runs in some other language. You could handle this in either of

-two ways:</p>

-

-<ul>

-  <li>Create  one  layout with a field that you can programmatically enable or

-disable, based on the language, or</li>

-  <li>Have the main layout include another layout that  includes the changeable

-field. The second layout can have different configurations for different

-languages.</li>

-</ul>

-

-<h4>Avoid creating more resource files and text strings than you need</h4>

-

-<p>You probably do not need to create a locale-specific

-alternative for every resource in your application. For example, the layout

-defined in the <code>res/layout/main.xml</code> file might work in any locale,

-in which case there would be no need to create any alternative layout files.

-</p>

-

-<p>Also, you might not need to create alternative text for every

-string. For example, assume the following:</p>

-

-<ul>

-  <li>Your application's default language is American

-English. Every string that the application uses is defined, using American

-English spellings, in <code>res/values/strings.xml</code>. </li>

-

-  <li>For  a few important phrases, you want to provide

-British English spelling. You want these alternative strings to be used when your

-application runs on a device in the United Kingdom. </li>

-</ul>

-

-<p>To do this, you could create a small file called

-<code>res/values-en-rGB/strings.xml</code> that includes only the strings that

-should be different when the application  runs in the U.K. For all the rest of

-the strings, the application will fall back to the defaults and use what is

-defined in <code>res/values/strings.xml</code>.</p>

-

-<h4>Use the Android Context object for manual locale lookup</h4>

-

-<p>You can look up the locale using the {@link android.content.Context} object

-that Android makes available:</p>

-

-<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>

-

-<h2 id="testing">Testing Localized Applications</h2>

-

-<h3 id="device">Testing on a Device</h3>

-<p>Keep in mind that the device you are testing may be significantly different from 

-	the devices available to consumers in other geographies. The locales available 

-	on your device may differ from those available on other devices. Also, the 

-	resolution and density of the device screen may differ, which could affect 

-	the display of strings and drawables in your UI.</p>

-

-<p>To change the locale or language on a device, use the Settings application.</p>

-

-<h3 id="emulator">Testing on an Emulator</h3>

-

-<p>For details about using the emulator, see See <a

-href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>

-<h4>Creating and using a custom locale</h4>

-

-<p>A &quot;custom&quot; locale is a language/region combination that the Android

-system image does not explicitly support. (For a list of supported locales in

-Android platforms see the Version Notes in the <a

-href="{@docRoot}sdk/index.html">SDK</a> tab). You can test

-how your application will run in a custom locale by creating a custom locale in

-the emulator. There are two ways to do this:</p>

-

-<ul>

-  <li>Use the Custom Locale application, which is accessible from the

-Application tab. (After you create a custom locale, switch to it by 

-pressing and holding the locale name.)</li>

-  <li>Change to a custom locale from the adb shell, as described below.</li>

-</ul>

-

-<p>When you set the emulator to a locale that is not available in the Android

-system image, the system itself will display in its default language. Your

-application, however, should localize properly.</p>

-

-<h4>Changing the emulator locale from the adb shell</h4>

-

-<p>To change the locale in the emulator by using the adb shell. </p>

-

-<ol>

-  <li>Pick the locale you want to test and determine its BCP-47 language tag, for

-example, Canadian French would be <code>fr-CA</code>.<br>

-  </li>

-  <li>Launch an emulator.</li>

-  <li>From a command-line shell on the host computer, run the following

-command:<br>

-    <code>adb shell</code><br>

-  or if you have a device attached, specify that you want the emulator by adding

-the <code>-e</code> option:<br>

-  <code>adb -e shell</code></li>

-  <li>At  the  adb shell prompt (<code>#</code>), run this command: <br>

-    <code>setprop persist.sys.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>

-    </code>Replace bracketed sections with the  appropriate codes from Step

-1.</li>

-</ol>

-

-<p>For instance, to test in Canadian French:</p>

-

-<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>

-

-<p>This will cause the emulator  to restart. (It will look like a full reboot,

-but it is not.) Once the Home screen appears again, re-launch your application (for

-example, click the Run icon in Eclipse), and the application will launch with

-the new locale. </p>

-

-<h3 id="test-for-default">Testing for Default Resources</h3>

-<p>Here's how to test whether an application includes every string resource that it needs:  </p>

-<ol><li>Set the emulator or device to a language that your application does not 

-	support. For example, if the application has French strings in 

-	<code>res/values-fr/</code> but does not have any Spanish strings in 

-	<code>res/values-es/</code>, then set the emulator's locale to Spanish. 

-	(You can use the Custom Locale application to set the emulator to an 

-	unsupported locale.)</li>

-	<li>Run the application.</li>  

-<li>If the application shows an error message and a Force Close button, it might 

-	be looking for a string that is not available. Make sure that your 

-	<code>res/values/strings.xml</code> file includes a definition for 

-	every string that the application uses.</li>

-</ol> 

-</p> 

-

-<p>If the test is successful, repeat it for other types of 

-	configurations. For example, if the application has a layout file called 

-	<code>res/layout-land/main.xml</code> but does not contain a file called 

-	<code>res/layout-port/main.xml</code>, then set the emulator or device to 

-	portrait orientation and see if the application will run. 

-

-

-

+page.title=Localizing with Resources
+parent.title=Application Resources
+page.tags="localizing","localization","resources", "formats", "l10n"
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+    <div id="qv">
+
+<h2>Quickview</h2>
+
+<ul>
+  <li>Use resource sets to create a localized app.</li>
+  <li>Android loads the correct resource set for the user's language and locale.</li>
+  <li>If localized resources are not available, Android loads your default resources.</li>
+</ul>
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>
+<li><a href="#using-framework">Using Resources for Localization</a></li>
+<li><a href="#strategies">Localization Tips</a></li>
+<li><a href="#testing">Testing Localized Applications</a></li>
+</ol>
+
+<h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>
+    <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>
+    <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>
+    <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>
+</ol>
+</div>
+</div>
+
+<p>Android will run on many  devices in many  regions. To reach the most users,
+your application should handle text, audio files, numbers, currency, and
+graphics in ways appropriate to the locales where your application will be used.
+</p>
+
+<p>This document describes best practices for localizing Android
+applications. The principles apply whether you are developing your application  
+using ADT with Eclipse, Ant-based tools, or any other IDE. </p>
+
+<p>You should already have a working knowledge of Java and be  familiar with
+Android resource loading, the declaration of user interface elements in XML,
+development considerations such as Activity lifecycle, and general principles of
+internationalization and localization. </p>
+
+<p>It is good practice to use the Android resource framework to separate the
+localized aspects of your application as much as possible from the core Java
+functionality:</p>
+
+<ul>
+  <li>You can put most or all of the <em>contents</em> of your application's
+user interface into resource files, as described in this document and in <a
+href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>
+  <li>The <em>behavior</em> of the user interface, on the other hand, is driven
+by your Java code. 
+    For example, if users input data that needs to be formatted or sorted
+differently depending on locale, then you would use Java to handle the data
+programmatically. This document does not cover how to  localize your Java code.
+</li>
+</ul>
+
+<p>For a short guide to localizing strings in your app, see the training lesson, <a
+href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>
+
+
+<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>
+
+<p>Resources are text strings, layouts, sounds, graphics, and any other static
+data that your  Android application  needs. An application can include multiple
+sets of resources, each customized for a different device configuration. When a
+user runs the application,  Android    automatically selects and loads the 
+resources that best match the device.</p>
+
+<p>(This document focuses on localization and locale. For a complete description
+of resource-switching and all the types of configurations that you can
+specify &#8212; screen orientation, touchscreen type, and so on &#8212; see <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
+Alternative Resources</a>.)</p>
+
+<table border="0" cellspacing="0" cellpadding="0">
+  <tr border="0">
+    <td width="180" style="border: 0pt none ;"><p class="special-note">
+    <strong>When you write your application:</strong>
+    <br><br>
+    You create a set of default resources, plus alternatives to be used in
+    different locales.</p></td>
+    <td style="border: 0pt none; padding:0">
+    <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow" 
+    width="51" height="17"></p></td>
+    <td width="180" style="border: 0pt none ;"><p class="special-note">
+    <strong>When a user runs your application:</strong>
+    <br><br>The Android system selects which resources to load, based on the
+    device's locale.</p></td>
+  </tr>
+</table>
+
+<p>When you write your application, you create default and alternative resources
+for your application to use. To create  resources, you place files within
+specially named subdirectories of the project's <code>res/</code> directory.
+</p>
+
+
+
+<h3 id="defaults-r-important">Why Default Resources Are Important</h3>
+
+<p>Whenever the application runs in a locale for which you have not provided
+locale-specific text,  Android will load the default strings from
+<code>res/values/strings.xml</code>. If this default  file is absent, or if it 
+is missing a string that your application needs, then your application will not run 
+and will show an error. 
+The example below illustrates what can happen when the default text file is incomplete. </p>
+
+<p><em>Example:</em>
+<p>An application's Java code refers to just two strings, <code>text_a</code> and 
+	<code>text_b</code>. This application includes a localized resource file 
+	(<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and 
+	<code>text_b</code> in English. This application also includes a default 
+	resource file (<code>res/values/strings.xml</code>) that includes a
+definition for <code>text_a</code>, but not for <code>text_b</code>:
+<ul>
+  <li>This application might compile without a problem. An IDE such as Eclipse 
+  	will not highlight any errors if a resource is missing.</li>
+  <li>When this application is launched on a device with locale set to English, 
+  	the application  might run without a problem, because 
+  	<code>res/values-en/strings.xml</code> contains both of the needed text 
+  	strings.</li>
+  <li>However, <strong>the user  will see an error message and a Force Close 
+  	button</strong> when this application is launched on a device set to a 
+  	language other than English. The application will not load.</li>
+</ul>
+
+
+<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code> 
+	file exists and that it defines every needed string. The situation applies to 
+	all types of resources, not just strings: You 
+	need to create a  set of default resource files containing all 
+	the resources that your application calls upon &#8212; layouts, drawables, 
+	animations, etc. For information about testing, see <a href="#test-for-default">
+	Testing for Default Resources</a>.</p>
+
+<h2 id="using-framework">Using Resources for Localization</h2>
+
+<h3 id="creating-defaults">How to Create Default Resources</h3>
+
+<p>Put the application's default text in
+a file with the following location and name:</p>
+<p><code>&nbsp;&nbsp;&nbsp;&nbsp;res/values/strings.xml</code> (required directory)</p>
+
+<p>The text strings in <code>res/values/strings.xml</code> should  use the
+default language, which is the language that you expect most of your application's users to
+speak.  </p>
+
+<p>The default resource set must also include any default drawables and layouts, 
+	and can include other types of resources such as animations. 
+<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/drawable/</code>(required directory holding at least
+  one graphic file, for the application's icon on Google Play)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/layout/</code> (required directory holding an XML
+  file that defines the default layout)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/anim/</code> (required if you have any 
+  <code>res/anim-<em>&lt;qualifiers&gt;</em></code> folders)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/xml/</code> (required if you have any 
+  <code>res/xml-<em>&lt;qualifiers&gt;</em></code> folders)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/raw/</code> (required if you have any 
+  <code>res/raw-<em>&lt;qualifiers&gt;</em></code> folders)
+</p>
+
+<p class="note"><strong>Tip:</strong> In your code, examine each reference to 
+	an Android resource. Make sure that a default resource is defined for each
+	one. Also make sure that the default string file is complete: A <em>
+	localized</em> string file can contain a subset of the strings, but the 
+	<em>default</em> string file must contain them all. 
+</p>
+
+<h3 id="creating-alternatives">How to Create Alternative Resources</h3>
+
+<p>A large part of localizing an application is providing alternative text for
+different languages. In some cases you will also provide alternative graphics,
+sounds, layouts, and other locale-specific resources. </p>
+
+<p>An application can specify many <code>res/<em>&lt;qualifiers&gt;</em>/</code>
+directories, each with different qualifiers. To create an alternative resource for
+a different locale, you use a qualifier that specifies a language or a 
+language-region combination. (The name of a resource directory must conform 
+to the naming scheme described in 
+<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
+Alternative Resources</a>,
+or else it will not compile.)</p>
+
+<p><em>Example:</em></p>
+
+<p>Suppose that your application's default language is English. Suppose also
+that you want to localize all the text in your application to French, and most
+of the text in your application (everything except the application's title) to
+Japanese. In this case, you could create three alternative <code>strings.xml</code>
+files, each stored in a locale-specific resource directory:</p>
+
+<ol>
+  <li><code>res/values/strings.xml</code><br>
+    Contains  English text for all  the strings that the application uses,
+including text for a string named <code>title</code>.</li>
+  <li><code>res/values-fr/strings.xml</code><br>
+    Contain French text for all  the strings, including <code>title</code>.</li>
+  <li><code>res/values-ja/strings.xml</code><br>
+    Contain Japanese text for all  the strings <em>except</em>
+<code>title</code>.<br>
+  <code></code></li>
+</ol>
+
+<p>If your Java code refers to <code>R.string.title</code>,  here is what will
+happen at runtime:</p>
+
+<ul>
+  <li>If the device is set to any language other than French, Android will load
+<code>title</code> from the <code>res/values/strings.xml</code> file.</li>
+  <li>If the device is set to French, Android will load <code>title</code> from
+the <code>res/values-fr/strings.xml</code> file.</li>
+</ul>
+
+<p>Notice that if the device is set to Japanese, Android will look for
+<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But
+because no such string is included in that file, Android will fall back to the
+default, and will load  <code>title</code> in English from the
+<code>res/values/strings.xml</code> file.  </p>
+
+<h3 id="resource-precedence">Which Resources Take Precedence?</h3>
+
+<p> If multiple resource files match a device's configuration, Android follows a
+set of rules in deciding which file to use. Among the qualifiers that can be
+specified in a resource directory name, <strong>locale almost always takes
+precedence</strong>. </p>
+<p><em>Example:</em></p>
+
+<p>Assume that an application  includes a default set of graphics and two other
+sets of graphics, each optimized for a different device setup:</p>
+
+<ul>
+  <li><code>res/drawable/</code><br>
+    Contains
+  default graphics.</li>
+  <li><code>res/drawable-small-land-stylus/</code><br>
+  Contains  graphics optimized for use with a device that expects input from a 
+  stylus and has a QVGA low-density screen in landscape orientation.</li>
+  <li><code>res/drawable-ja/</code> <br>
+  Contains  graphics optimized for use with Japanese.</li>
+</ul>
+
+<p>If the application runs on a device that is configured to use Japanese,
+Android will load graphics from  <code>res/drawable-ja/</code>, even if the
+device happens to be one that expects input from a stylus and has a QVGA 
+low-density screen in landscape orientation.</p>
+
+<p class="note"><strong>Exception:</strong> The only qualifiers that take
+precedence over locale in the selection process are MCC and MNC (mobile country
+code and mobile network code). </p>
+
+<p><em>Example:</em></p>
+
+<p>Assume that you have the following situation:</p>
+
+<ul>
+  <li>The application code calls for <code>R.string.text_a</code></li>
+  <li>Two relevant resource files are available:
+    <ul>
+      <li><code>res/values-mcc404/strings.xml</code>, which includes
+<code>text_a</code> in the application's default language, in this case
+English.</li>
+      <li><code>res/values-hi/strings.xml</code>, which includes
+<code>text_a</code> in Hindi.</li>
+    </ul>
+  </li>
+  <li>The application is running on a device that has the following
+configuration:
+    <ul>
+      <li>The SIM card is connected to a mobile network in India (MCC 404).</li>
+      <li>The language is set to Hindi (<code>hi</code>).</li>
+    </ul>
+  </li>
+</ul>
+
+<p>Android will load <code>text_a</code> from
+<code>res/values-mcc404/strings.xml</code> (in English), even if the device is
+configured for Hindi. That is because in the resource-selection process, Android
+will prefer an MCC match over a language match. </p>
+
+<p>The selection process is not always as straightforward as these examples
+suggest. Please read  <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds
+the Best-matching Resource</a> for a more nuanced description of the
+process. All the qualifiers are described and listed in order of
+precedence in <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing
+Alternative Resources</a>.</p>
+
+<h3 id="referring-to-resources">Referring to Resources in Java</h3>
+
+<p>In your application's Java code, you refer to  resources using the syntax
+<code>R.<em>resource_type</em>.<em>resource_name</em></code> or
+<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>
+For more about this, see <a
+href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>
+
+<h2 id="checklist">Localization Checklist</h2>
+
+<p>For a complete overview of the process of localizing and distributing an Android application,
+see the <a href="{@docRoot}distribute/tools/localization-checklist.html">Localization
+Checklist</a> document.</p>
+
+<h2 id="strategies">Localization Tips</h2>
+
+<h4 id="failing2">Design your application  to work in any locale</h4>
+
+<p>You cannot assume anything about the device on which a user will
+run your application. The device might have hardware that you were not
+anticipating, or it might be set to a locale that you did not plan for or that 
+you cannot test. Design your application so that it will function normally or fail gracefully no 
+matter what device it runs on.</p>
+
+<p class="note"><strong>Important:</strong> Make sure that your application
+includes a full set of default resources.</p> <p>Make sure to include
+<code>res/drawable/</code> and a <code>res/values/</code> folders (without any
+additional modifiers in the folder names) that contain all the images and text
+that your application will need. </p>
+
+<p>If an application is missing even one default resource, it will not run on a 
+	device that is set to an unsupported locale. For example, the 
+	<code>res/values/strings.xml</code> default file might lack one string that 
+	the application needs: When the application runs in an unsupported locale and 
+	attempts to load <code>res/values/strings.xml</code>, the user will see an 
+	error message and a Force Close button. An IDE such as Eclipse will not 
+	highlight this kind of error, and you will not see the problem when you 
+	test the application on a device or emulator that is set to a supported locale.</p>
+
+<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>
+
+<h4>Design a flexible layout</h4>
+
+<p> If you need to rearrange your layout to fit a certain language (for example
+German with its long words), you can create an alternative layout for that
+language (for example <code>res/layout-de/main.xml</code>). However, doing this
+can make your application harder to maintain.  It is better to create a single
+layout that is more flexible.</p>
+
+<p>Another typical situation is a language that requires something different in
+its layout. For example, you might have a contact form that should include  two
+name fields when the application runs in Japanese, but three name fields when
+the application  runs in some other language. You could handle this in either of
+two ways:</p>
+
+<ul>
+  <li>Create  one  layout with a field that you can programmatically enable or
+disable, based on the language, or</li>
+  <li>Have the main layout include another layout that  includes the changeable
+field. The second layout can have different configurations for different
+languages.</li>
+</ul>
+
+<h4>Avoid creating more resource files and text strings than you need</h4>
+
+<p>You probably do not need to create a locale-specific
+alternative for every resource in your application. For example, the layout
+defined in the <code>res/layout/main.xml</code> file might work in any locale,
+in which case there would be no need to create any alternative layout files.
+</p>
+
+<p>Also, you might not need to create alternative text for every
+string. For example, assume the following:</p>
+
+<ul>
+  <li>Your application's default language is American
+English. Every string that the application uses is defined, using American
+English spellings, in <code>res/values/strings.xml</code>. </li>
+
+  <li>For  a few important phrases, you want to provide
+British English spelling. You want these alternative strings to be used when your
+application runs on a device in the United Kingdom. </li>
+</ul>
+
+<p>To do this, you could create a small file called
+<code>res/values-en-rGB/strings.xml</code> that includes only the strings that
+should be different when the application  runs in the U.K. For all the rest of
+the strings, the application will fall back to the defaults and use what is
+defined in <code>res/values/strings.xml</code>.</p>
+
+<h4>Use the Android Context object for manual locale lookup</h4>
+
+<p>You can look up the locale using the {@link android.content.Context} object
+that Android makes available:</p>
+
+<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>
+
+<h2 id="testing">Testing Localized Applications</h2>
+
+<h3 id="device">Testing on a Device</h3>
+<p>Keep in mind that the device you are testing may be significantly different from 
+	the devices available to consumers in other geographies. The locales available 
+	on your device may differ from those available on other devices. Also, the 
+	resolution and density of the device screen may differ, which could affect 
+	the display of strings and drawables in your UI.</p>
+
+<p>To change the locale or language on a device, use the Settings application.</p>
+
+<h3 id="emulator">Testing on an Emulator</h3>
+
+<p>For details about using the emulator, see See <a
+href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>
+<h4>Creating and using a custom locale</h4>
+
+<p>A &quot;custom&quot; locale is a language/region combination that the Android
+system image does not explicitly support. (For a list of supported locales in
+Android platforms see the Version Notes in the <a
+href="{@docRoot}sdk/index.html">SDK</a> tab). You can test
+how your application will run in a custom locale by creating a custom locale in
+the emulator. There are two ways to do this:</p>
+
+<ul>
+  <li>Use the Custom Locale application, which is accessible from the
+Application tab. (After you create a custom locale, switch to it by 
+pressing and holding the locale name.)</li>
+  <li>Change to a custom locale from the adb shell, as described below.</li>
+</ul>
+
+<p>When you set the emulator to a locale that is not available in the Android
+system image, the system itself will display in its default language. Your
+application, however, should localize properly.</p>
+
+<h4>Changing the emulator locale from the adb shell</h4>
+
+<p>To change the locale in the emulator by using the adb shell. </p>
+
+<ol>
+  <li>Pick the locale you want to test and determine its BCP-47 language tag, for
+example, Canadian French would be <code>fr-CA</code>.<br>
+  </li>
+  <li>Launch an emulator.</li>
+  <li>From a command-line shell on the host computer, run the following
+command:<br>
+    <code>adb shell</code><br>
+  or if you have a device attached, specify that you want the emulator by adding
+the <code>-e</code> option:<br>
+  <code>adb -e shell</code></li>
+  <li>At  the  adb shell prompt (<code>#</code>), run this command: <br>
+    <code>setprop persist.sys.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>
+    </code>Replace bracketed sections with the  appropriate codes from Step
+1.</li>
+</ol>
+
+<p>For instance, to test in Canadian French:</p>
+
+<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>
+
+<p>This will cause the emulator  to restart. (It will look like a full reboot,
+but it is not.) Once the Home screen appears again, re-launch your application (for
+example, click the Run icon in Eclipse), and the application will launch with
+the new locale. </p>
+
+<h3 id="test-for-default">Testing for Default Resources</h3>
+<p>Here's how to test whether an application includes every string resource that it needs:  </p>
+<ol><li>Set the emulator or device to a language that your application does not 
+	support. For example, if the application has French strings in 
+	<code>res/values-fr/</code> but does not have any Spanish strings in 
+	<code>res/values-es/</code>, then set the emulator's locale to Spanish. 
+	(You can use the Custom Locale application to set the emulator to an 
+	unsupported locale.)</li>
+	<li>Run the application.</li>  
+<li>If the application shows an error message and a Force Close button, it might 
+	be looking for a string that is not available. Make sure that your 
+	<code>res/values/strings.xml</code> file includes a definition for 
+	every string that the application uses.</li>
+</ol> 
+</p> 
+
+<p>If the test is successful, repeat it for other types of 
+	configurations. For example, if the application has a layout file called 
+	<code>res/layout-land/main.xml</code> but does not contain a file called 
+	<code>res/layout-port/main.xml</code>, then set the emulator or device to 
+	portrait orientation and see if the application will run. 
+
+
+
diff --git a/docs/overview-ext.html b/docs/overview-ext.html
index 5720245..f80d629 100644
--- a/docs/overview-ext.html
+++ b/docs/overview-ext.html
@@ -1,8 +1,8 @@
-<body>

-Some random libraries that we've imported:

-<ul>

-    <li>GData</li>

-    <li>Apache commons HTTPClient</li>

-    <li>A sax parser</li>

-</ul>

-</body>

+<body>
+Some random libraries that we've imported:
+<ul>
+    <li>GData</li>
+    <li>Apache commons HTTPClient</li>
+    <li>A sax parser</li>
+</ul>
+</body>
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 3973f2f..aa81b91 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -37,22 +37,26 @@
 public final class Outline {
     private static final float RADIUS_UNDEFINED = Float.NEGATIVE_INFINITY;
 
-    private static final int MODE_EMPTY = 0;
-    private static final int MODE_RECT = 1;
-    private static final int MODE_CONVEX_PATH = 2;
+    /** @hide */
+    public static final int MODE_EMPTY = 0;
+    /** @hide */
+    public static final int MODE_ROUND_RECT = 1;
+    /** @hide */
+    public static final int MODE_CONVEX_PATH = 2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = false,
             value = {
                     MODE_EMPTY,
-                    MODE_RECT,
+                    MODE_ROUND_RECT,
                     MODE_CONVEX_PATH,
             })
     public @interface Mode {}
 
+    /** @hide */
     @Mode
-    private int mMode = MODE_EMPTY;
+    public int mMode = MODE_EMPTY;
 
     /** @hide */
     public final Path mPath = new Path();
@@ -176,7 +180,7 @@
             return;
         }
 
-        mMode = MODE_RECT;
+        mMode = MODE_ROUND_RECT;
         mRect.set(left, top, right, bottom);
         mRadius = radius;
         mPath.rewind();
@@ -199,7 +203,7 @@
      *         bounds, or {@code false} if no outline bounds are set
      */
     public boolean getRect(@NonNull Rect outRect) {
-        if (mMode != MODE_RECT) {
+        if (mMode != MODE_ROUND_RECT) {
             return false;
         }
         outRect.set(mRect);
@@ -270,7 +274,7 @@
      * Offsets the Outline by (dx,dy)
      */
     public void offset(int dx, int dy) {
-        if (mMode == MODE_RECT) {
+        if (mMode == MODE_ROUND_RECT) {
             mRect.offset(dx, dy);
         } else if (mMode == MODE_CONVEX_PATH) {
             mPath.offset(dx, dy);
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 46a0f43..35385eb 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -1416,6 +1416,9 @@
                 Log.d(LOGTAG, "on finished called from native");
             }
             mStarted = false;
+            // Invalidate in the end of the animation to make sure the data in
+            // RT thread is synced back to UI thread.
+            invalidateOwningView();
             if (mListener != null) {
                 mListener.onAnimationEnd(null);
             }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 52fe973..1ccc59a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3935,7 +3935,9 @@
         if (Res_GETPACKAGE(resID)+1 == 0) {
             ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
         } else {
+#ifndef STATIC_ANDROIDFW_FOR_TOOLS
             ALOGW("No known package when getting name for resource number 0x%08x", resID);
+#endif
         }
         return false;
     }
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1f17851..be816f7 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -252,6 +252,7 @@
     tests/unit/LinearAllocatorTests.cpp \
     tests/unit/MatrixTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
+    tests/unit/RenderNodeTests.cpp \
     tests/unit/SkiaBehaviorTests.cpp \
     tests/unit/StringUtilsTests.cpp \
     tests/unit/TextDropShadowCacheTests.cpp \
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index ea4f4eb..f43bf86 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -195,7 +195,7 @@
 }
 
 static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
-        const TextOp& op, const BakedOpState& state) {
+        const TextOp& op, const BakedOpState& textOpState) {
     renderer.caches().textureState().activateTexture(0);
 
     PaintUtils::TextShadow textShadow;
@@ -216,13 +216,41 @@
 
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
-            .setRoundRectClipState(state.roundRectClipState)
+            .setRoundRectClipState(textOpState.roundRectClipState)
             .setMeshTexturedUnitQuad(nullptr)
-            .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha)
-            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, textOpState.alpha)
+            .setTransform(textOpState.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
             .build();
-    renderer.renderGlop(state, glop);
+
+    // Compute damage bounds and clip (since may differ from those in textOpState).
+    // Bounds should be same as text op, but with dx/dy offset and radius outset
+    // applied in local space.
+    auto& transform = textOpState.computedState.transform;
+    Rect shadowBounds = op.unmappedBounds; // STROKE
+    const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
+    if (expandForStroke) {
+        shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
+    }
+    shadowBounds.translate(textShadow.dx, textShadow.dy);
+    shadowBounds.outset(textShadow.radius, textShadow.radius);
+    transform.mapRect(shadowBounds);
+    if (CC_UNLIKELY(expandForStroke &&
+            (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
+        shadowBounds.outset(0.5f);
+    }
+
+    auto clipState = textOpState.computedState.clipState;
+    if (clipState->mode != ClipMode::Rectangle
+            || !clipState->rect.contains(shadowBounds)) {
+        // need clip, so pass it and clip bounds
+        shadowBounds.doIntersect(clipState->rect);
+    } else {
+        // don't need clip, ignore
+        clipState = nullptr;
+    }
+
+    renderer.renderGlop(&shadowBounds, clipState, glop);
 }
 
 enum class TextRenderType {
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 59f0d7c..181b343 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,6 +45,7 @@
         , regions(stdAllocator)
         , referenceHolders(stdAllocator)
         , functors(stdAllocator)
+        , pushStagingFunctors(stdAllocator)
         , hasDrawOps(false) {
 }
 
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 60cc7ba..e209e2a 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -110,6 +110,16 @@
 };
 
 /**
+ * Functor that can be used for objects with data in both UI thread and RT to keep the data
+ * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
+ */
+struct PushStagingFunctor {
+    PushStagingFunctor() {}
+    virtual ~PushStagingFunctor() {}
+    virtual void operator ()() {}
+};
+
+/**
  * Data structure that holds the list of commands used in display list stream
  */
 class DisplayList {
@@ -142,6 +152,7 @@
 
     const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
     const LsaVector<Functor*>& getFunctors() const { return functors; }
+    const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
 
     size_t addChild(NodeOpType* childOp);
 
@@ -183,6 +194,11 @@
     // List of functors
     LsaVector<Functor*> functors;
 
+    // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+    // but a callback during sync DisplayList, unlike the list of functors defined above, which
+    // gets special treatment exclusive for webview.
+    LsaVector<PushStagingFunctor*> pushStagingFunctors;
+
     bool hasDrawOps; // only used if !HWUI_NEW_OPS
 
     void cleanupResources();
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 2dccf32..c6e92ab 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -415,7 +415,8 @@
 
 void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
     mDisplayList->ref(tree);
-    addDrawOp(new (alloc()) DrawVectorDrawableOp(tree));
+    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+    addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
 }
 
 void DisplayListCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count,
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 516e619..59f073f 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1110,15 +1110,14 @@
 
 class DrawVectorDrawableOp : public DrawOp {
 public:
-    DrawVectorDrawableOp(VectorDrawableRoot* tree)
-            : DrawOp(nullptr), mTree(tree) {}
+    DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds)
+            : DrawOp(nullptr), mTree(tree), mDst(bounds) {}
 
     virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
         const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty();
         SkPaint* paint = mTree->getPaint();
-        const SkRect bounds = mTree->getBounds();
         renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()),
-                bounds, paint);
+                mDst, paint);
     }
 
     virtual void output(int level, uint32_t logFlags) const override {
@@ -1129,6 +1128,7 @@
 
 private:
     VectorDrawableRoot* mTree;
+    SkRect mDst;
 
 };
 
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 704bd69..6a96634 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -163,11 +163,13 @@
         GLenum dst;
     } blend;
 
+#if !HWUI_NEW_OPS
     /**
      * Bounds of the drawing command in layer space. Only mapped into layer
      * space once GlopBuilder::build() is called.
      */
     Rect bounds; // TODO: remove for HWUI_NEW_OPS
+#endif
 
     /**
      * Additional render state to enumerate:
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2799def..7d4f410 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -492,7 +492,9 @@
 
     mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
     mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = destination;
+#endif
     return *this;
 }
 
@@ -516,7 +518,9 @@
 
     mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
     mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = destination;
+#endif
     return *this;
 }
 
@@ -524,8 +528,10 @@
     TRIGGER_STAGE(kModelViewStage);
 
     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = source;
     mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
     return *this;
 }
 
@@ -545,8 +551,10 @@
     }
 
     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+#if !HWUI_NEW_OPS
     mOutGlop->bounds = source;
     mOutGlop->bounds.translate(offsetX, offsetY);
+#endif
     return *this;
 }
 
@@ -643,7 +651,9 @@
 
     // Final step: populate program and map bounds into render target space
     mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+#if !HWUI_NEW_OPS
     mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds);
+#endif
 }
 
 void GlopBuilder::dump(const Glop& glop) {
@@ -683,7 +693,9 @@
     ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState);
 
     ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst);
+#if !HWUI_NEW_OPS
     ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds));
+#endif
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 76e587e..d1ff670 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -15,6 +15,8 @@
  */
 #include "JankTracker.h"
 
+#include "Properties.h"
+
 #include <algorithm>
 #include <cutils/ashmem.h>
 #include <cutils/log.h>
@@ -54,32 +56,35 @@
 static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
 
 /*
- * Frames that are exempt from jank metrics.
- * First-draw frames, for example, are expected to
- * be slow, this is hidden from the user with window animations and
- * other tricks
- *
- * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * We don't track direct-drawing via Surface:lockHardwareCanvas()
  * for now
  *
  * TODO: kSurfaceCanvas can negatively impact other drawing by using up
  * time on the RenderThread, figure out how to attribute that as a jank-causer
  */
-static const int64_t EXEMPT_FRAMES_FLAGS
-        = FrameInfoFlags::WindowLayoutChanged
-        | FrameInfoFlags::SurfaceCanvas;
+static const int64_t EXEMPT_FRAMES_FLAGS = FrameInfoFlags::SurfaceCanvas;
 
 // The bucketing algorithm controls so to speak
 // If a frame is <= to this it goes in bucket 0
-static const uint32_t kBucketMinThreshold = 7;
+static const uint32_t kBucketMinThreshold = 5;
 // If a frame is > this, start counting in increments of 2ms
 static const uint32_t kBucket2msIntervals = 32;
 // If a frame is > this, start counting in increments of 4ms
 static const uint32_t kBucket4msIntervals = 48;
 
+// For testing purposes to try and eliminate test infra overhead we will
+// consider any unknown delay of frame start as part of the test infrastructure
+// and filter it out of the frame profile data
+static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
+
+// The interval of the slow frame histogram
+static const uint32_t kSlowFrameBucketIntervalMs = 50;
+// The start point of the slow frame bucket in ms
+static const uint32_t kSlowFrameBucketStartMs = 150;
+
 // This will be called every frame, performance sensitive
 // Uses bit twiddling to avoid branching while achieving the packing desired
-static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime, uint32_t max) {
+static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
     uint32_t index = static_cast<uint32_t>(ns2ms(frameTime));
     // If index > kBucketMinThreshold mask will be 0xFFFFFFFF as a result
     // of negating 1 (twos compliment, yaay) else mask will be 0
@@ -97,7 +102,7 @@
     // be a pretty garbage value right now. However, mask is 0 so we'll end
     // up with the desired result of 0.
     index = (index - kBucketMinThreshold) & mask;
-    return index < max ? index : max;
+    return index;
 }
 
 // Only called when dumping stats, less performance sensitive
@@ -204,63 +209,34 @@
 
 }
 
-static bool shouldReplace(SlowFrame& existing, SlowFrame& candidate) {
-    if (candidate.whenHours - existing.whenHours >= 24) {
-        // If the old slowframe is over 24 hours older than the candidate,
-        // replace it. It's too stale
-        return true;
-    }
-    if (candidate.frametimeMs > existing.frametimeMs) {
-        return true;
-    }
-    return false;
-}
-
-void JankTracker::updateSlowest(const FrameInfo& frame) {
-    uint16_t durationMs = static_cast<uint16_t>(std::min(
-            ns2ms(frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync]),
-            static_cast<nsecs_t>(std::numeric_limits<uint16_t>::max())));
-    uint16_t startHours = static_cast<uint16_t>(std::lround(
-            ns2s(frame[FrameInfoIndex::IntendedVsync]) / 3600.0f));
-    SlowFrame* toReplace = nullptr;
-    SlowFrame thisFrame{startHours, durationMs};
-    // First find the best candidate for replacement
-    for (SlowFrame& existing : mData->slowestFrames) {
-        // If we should replace the current data with the replacement candidate,
-        // it means the current data is worse than the replacement candidate
-        if (!toReplace || shouldReplace(existing, *toReplace)) {
-            toReplace = &existing;
-        }
-    }
-    // Now see if we should replace it
-    if (shouldReplace(*toReplace, thisFrame)) {
-        *toReplace = thisFrame;
-    }
-}
-
 void JankTracker::addFrame(const FrameInfo& frame) {
     mData->totalFrameCount++;
     // Fast-path for jank-free frames
     int64_t totalDuration =
-            frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync];
-    uint32_t framebucket = frameCountIndexForFrameTime(
-            totalDuration, mData->frameCounts.size() - 1);
+            frame[FrameInfoIndex::FrameCompleted] - frame[sFrameStart];
+    uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
     // Keep the fast path as fast as possible.
     if (CC_LIKELY(totalDuration < mFrameInterval)) {
         mData->frameCounts[framebucket]++;
         return;
     }
 
-    // For slowest frames we are still interested in frames that are otherwise
-    // exempt (such as first-draw). Although those frames don't directly impact
-    // smoothness, they do impact responsiveness.
-    updateSlowest(frame);
-
+    // Only things like Surface.lockHardwareCanvas() are exempt from tracking
     if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
         return;
     }
 
-    mData->frameCounts[framebucket]++;
+    if (framebucket <= mData->frameCounts.size()) {
+        mData->frameCounts[framebucket]++;
+    } else {
+        framebucket = (ns2ms(totalDuration) - kSlowFrameBucketStartMs)
+                / kSlowFrameBucketIntervalMs;
+        framebucket = std::min(framebucket,
+                static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
+        framebucket = std::max(framebucket, 0u);
+        mData->slowFrameCounts[framebucket]++;
+    }
+
     mData->jankFrameCount++;
 
     for (int i = 0; i < NUM_BUCKETS; i++) {
@@ -280,6 +256,9 @@
 }
 
 void JankTracker::dumpData(const ProfileData* data, int fd) {
+    if (sFrameStart != FrameInfoIndex::IntendedVsync) {
+        dprintf(fd, "\nNote: Data has been filtered!");
+    }
     dprintf(fd, "\nStats since: %" PRIu64 "ns", data->statStartTime);
     dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
     dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
@@ -288,14 +267,18 @@
     dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
     dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
     dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
-    dprintf(fd, "\nSlowest frames over last 24h: ");
-    for (auto& slowFrame : data->slowestFrames) {
-        if (!slowFrame.frametimeMs) continue;
-        dprintf(fd, "%ums ", slowFrame.frametimeMs);
-    }
     for (int i = 0; i < NUM_BUCKETS; i++) {
         dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
     }
+    dprintf(fd, "\nHISTOGRAM:");
+    for (size_t i = 0; i < data->frameCounts.size(); i++) {
+        dprintf(fd, " %ums=%u", frameTimeForFrameCountIndex(i),
+                data->frameCounts[i]);
+    }
+    for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
+        dprintf(fd, " %zums=%u", (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs,
+                data->slowFrameCounts[i]);
+    }
     dprintf(fd, "\n");
 }
 
@@ -305,11 +288,20 @@
     mData->totalFrameCount = 0;
     mData->jankFrameCount = 0;
     mData->statStartTime = systemTime(CLOCK_MONOTONIC);
+    sFrameStart = Properties::filterOutTestOverhead
+            ? FrameInfoIndex::HandleInputStart
+            : FrameInfoIndex::IntendedVsync;
 }
 
 uint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
     int pos = percentile * data->totalFrameCount / 100;
     int remaining = data->totalFrameCount - pos;
+    for (int i = data->slowFrameCounts.size() - 1; i >= 0; i--) {
+        remaining -= data->slowFrameCounts[i];
+        if (remaining <= 0) {
+            return (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs;
+        }
+    }
     for (int i = data->frameCounts.size() - 1; i >= 0; i--) {
         remaining -= data->frameCounts[i];
         if (remaining <= 0) {
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 1a4a489..84b8c3f 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -39,23 +39,18 @@
     NUM_BUCKETS,
 };
 
-struct SlowFrame {
-    uint16_t whenHours; // When this occurred in CLOCK_MONOTONIC in hours
-    uint16_t frametimeMs; // How long the frame took in ms
-};
-
 // Try to keep as small as possible, should match ASHMEM_SIZE in
 // GraphicsStatsService.java
 struct ProfileData {
     std::array<uint32_t, NUM_BUCKETS> jankTypeCounts;
     // See comments on kBucket* constants for what this holds
-    std::array<uint32_t, 55> frameCounts;
+    std::array<uint32_t, 57> frameCounts;
+    // Holds a histogram of frame times in 50ms increments from 150ms to 5s
+    std::array<uint16_t, 97> slowFrameCounts;
 
     uint32_t totalFrameCount;
     uint32_t jankFrameCount;
     nsecs_t statStartTime;
-
-    std::array<SlowFrame, 10> slowestFrames;
 };
 
 // TODO: Replace DrawProfiler with this
@@ -78,7 +73,6 @@
 private:
     void freeData();
     void setFrameInterval(nsecs_t frameIntervalNanos);
-    void updateSlowest(const FrameInfo& frame);
 
     static uint32_t findPercentile(const ProfileData* data, int p);
     static void dumpData(const ProfileData* data, int fd);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c099427..53ea7fa 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1413,7 +1413,9 @@
     if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
         // TODO: specify more clearly when a draw should dirty the layer.
         // is writing to the stencil the only time we should ignore this?
+#if !HWUI_NEW_OPS
         dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+#endif
         mDirty = true;
     }
 }
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index bbd8c72..6f68c2b 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -66,6 +66,8 @@
 
 bool Properties::waitForGpuCompletion = false;
 
+bool Properties::filterOutTestOverhead = false;
+
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {'\0',};
 
@@ -156,6 +158,8 @@
     textureCacheFlushRate = std::max(0.0f, std::min(1.0f,
             property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE)));
 
+    filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
+
     return (prevDebugLayersUpdates != debugLayersUpdates)
             || (prevDebugOverdraw != debugOverdraw)
             || (prevDebugStencilClip != debugStencilClip);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 249b5b0..171873d 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -151,6 +151,8 @@
  */
 #define PROPERTY_ENABLE_PARTIAL_UPDATES "debug.hwui.enable_partial_updates"
 
+#define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead"
+
 ///////////////////////////////////////////////////////////////////////////////
 // Runtime configuration properties
 ///////////////////////////////////////////////////////////////////////////////
@@ -294,6 +296,10 @@
     // Should be used only by test apps
     static bool waitForGpuCompletion;
 
+    // Should only be set by automated tests to try and filter out
+    // any overhead they add
+    static bool filterOutTestOverhead;
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 8f837f6..0932d65 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -53,7 +53,7 @@
     } else {
         animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
     }
-    mGroup->setPropertyValue(mPropertyId, animatedValue);
+    mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
 }
 
 inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
@@ -72,7 +72,7 @@
 
 void FullPathColorPropertyValuesHolder::setFraction(float fraction) {
     SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction);
-    mFullPath->setColorPropertyValue(mPropertyId, animatedValue);
+    mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
 }
 
 void FullPathPropertyValuesHolder::setFraction(float fraction) {
@@ -82,17 +82,17 @@
     } else {
         animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
     }
-    mFullPath->setPropertyValue(mPropertyId, animatedValue);
+    mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
 }
 
 void PathDataPropertyValuesHolder::setFraction(float fraction) {
     VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction);
-    mPath->setPathData(mPathData);
+    mPath->mutateProperties()->setData(mPathData);
 }
 
 void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
     float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
-    mTree->setRootAlpha(animatedValue);
+    mTree->mutateProperties()->setRootAlpha(animatedValue);
 }
 
 } // namepace uirenderer
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4f9cd68..b78497d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -430,10 +430,11 @@
 }
 
 void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
     mDisplayList->ref(tree);
     addOp(alloc().create_trivial<VectorDrawableOp>(
             tree,
-            Rect(tree->getBounds()),
+            Rect(tree->stagingProperties()->getBounds()),
             *(mState.currentSnapshot()->transform),
             getRecordedClip()));
 }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 61441ce..9578486 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -68,7 +68,7 @@
 }
 
 RenderNode::~RenderNode() {
-    deleteDisplayList();
+    deleteDisplayList(nullptr);
     delete mStagingDisplayList;
 #if HWUI_NEW_OPS
     LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!");
@@ -88,7 +88,7 @@
     // If mParentCount == 0 we are the sole reference to this RenderNode,
     // so immediately free the old display list
     if (!mParentCount && !mStagingDisplayList) {
-        deleteDisplayList();
+        deleteDisplayList(nullptr);
     }
 }
 
@@ -462,7 +462,7 @@
 }
 #endif
 
-void RenderNode::syncDisplayList() {
+void RenderNode::syncDisplayList(TreeObserver* observer) {
     // Make sure we inc first so that we don't fluctuate between 0 and 1,
     // which would thrash the layer cache
     if (mStagingDisplayList) {
@@ -470,13 +470,16 @@
             child->renderNode->incParentRefCount();
         }
     }
-    deleteDisplayList();
+    deleteDisplayList(observer);
     mDisplayList = mStagingDisplayList;
     mStagingDisplayList = nullptr;
     if (mDisplayList) {
         for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
             (*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
         }
+        for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
+            (*mDisplayList->getPushStagingFunctors()[i])();
+        }
     }
 }
 
@@ -486,15 +489,15 @@
         // Damage with the old display list first then the new one to catch any
         // changes in isRenderable or, in the future, bounds
         damageSelf(info);
-        syncDisplayList();
+        syncDisplayList(info.observer);
         damageSelf(info);
     }
 }
 
-void RenderNode::deleteDisplayList() {
+void RenderNode::deleteDisplayList(TreeObserver* observer) {
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
-            child->renderNode->decParentRefCount();
+            child->renderNode->decParentRefCount(observer);
         }
     }
     delete mDisplayList;
@@ -526,32 +529,35 @@
     }
 }
 
-void RenderNode::destroyHardwareResources() {
+void RenderNode::destroyHardwareResources(TreeObserver* observer) {
     if (mLayer) {
         destroyLayer(mLayer);
         mLayer = nullptr;
     }
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
-            child->renderNode->destroyHardwareResources();
+            child->renderNode->destroyHardwareResources(observer);
         }
         if (mNeedsDisplayListSync) {
             // Next prepare tree we are going to push a new display list, so we can
             // drop our current one now
-            deleteDisplayList();
+            deleteDisplayList(observer);
         }
     }
 }
 
-void RenderNode::decParentRefCount() {
+void RenderNode::decParentRefCount(TreeObserver* observer) {
     LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
     mParentCount--;
     if (!mParentCount) {
+        if (observer) {
+            observer->onMaybeRemovedFromTree(this);
+        }
         // If a child of ours is being attached to our parent then this will incorrectly
         // destroy its hardware resources. However, this situation is highly unlikely
         // and the failure is "just" that the layer is re-created, so this should
         // be safe enough
-        destroyHardwareResources();
+        destroyHardwareResources(observer);
     }
 }
 
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 8381925..b0136cf 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -68,6 +68,7 @@
 class SaveOp;
 class RestoreToCountOp;
 class TreeInfo;
+class TreeObserver;
 
 namespace proto {
 class RenderNode;
@@ -154,6 +155,14 @@
         }
     }
 
+    VirtualLightRefBase* getUserContext() const {
+        return mUserContext.get();
+    }
+
+    void setUserContext(VirtualLightRefBase* context) {
+        mUserContext = context;
+    }
+
     bool isPropertyFieldDirty(DirtyPropertyMask field) const {
         return mDirtyPropertyFields & field;
     }
@@ -187,7 +196,7 @@
     }
 
     ANDROID_API virtual void prepareTree(TreeInfo& info);
-    void destroyHardwareResources();
+    void destroyHardwareResources(TreeObserver* observer);
 
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -232,6 +241,12 @@
         mPositionListener.reset(listener);
     }
 
+    // This is only modified in MODE_FULL, so it can be safely accessed
+    // on the UI thread.
+    ANDROID_API bool hasParents() {
+        return mParentCount;
+    }
+
 private:
     typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
 
@@ -291,7 +306,7 @@
 
 
     void syncProperties();
-    void syncDisplayList();
+    void syncDisplayList(TreeObserver* observer);
 
     void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
     void pushStagingPropertiesChanges(TreeInfo& info);
@@ -302,13 +317,14 @@
 #endif
     void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
     void pushLayerUpdate(TreeInfo& info);
-    void deleteDisplayList();
+    void deleteDisplayList(TreeObserver* observer);
     void damageSelf(TreeInfo& info);
 
     void incParentRefCount() { mParentCount++; }
-    void decParentRefCount();
+    void decParentRefCount(TreeObserver* observer);
 
     String8 mName;
+    sp<VirtualLightRefBase> mUserContext;
 
     uint32_t mDirtyPropertyFields;
     RenderProperties mProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index f577785..5ebf545 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -155,6 +155,23 @@
         ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
                 (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
     }
+
+    if (getRevealClip().willClip()) {
+        Rect bounds;
+        getRevealClip().getBounds(&bounds);
+        ALOGD("%*s(Clip to reveal clip with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+                RECT_ARGS(bounds));
+    }
+
+    auto& outline = mPrimitiveFields.mOutline;
+    if (outline.getShouldClip()) {
+        if (outline.isEmpty()) {
+            ALOGD("%*s(Clip to empty outline)", level * 2, "");
+        } else if (outline.willClip()) {
+            ALOGD("%*s(Clip to outline with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
+                    RECT_ARGS(outline.getBounds()));
+        }
+    }
 }
 
 void RenderProperties::updateMatrix() {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 5d24fa0..1b459c1 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -747,11 +747,7 @@
 }
 
 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
-    const SkBitmap& bitmap = vectorDrawable->getBitmapUpdateIfDirty();
-    SkRect bounds = vectorDrawable->getBounds();
-    drawBitmap(bitmap, 0, 0, bitmap.width(), bitmap.height(),
-            bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
-            vectorDrawable->getPaint());
+    vectorDrawable->drawStaging(this);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index accd303..a43e544 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -32,6 +32,7 @@
 class DamageAccumulator;
 class LayerUpdateQueue;
 class OpenGLRenderer;
+class RenderNode;
 class RenderState;
 
 class ErrorHandler {
@@ -41,6 +42,17 @@
     ~ErrorHandler() {}
 };
 
+class TreeObserver {
+public:
+    // Called when a RenderNode's parent count hits 0.
+    // Due to the unordered nature of tree pushes, once prepareTree
+    // is finished it is possible that the node was "resurrected" and has
+    // a non-zero parent count.
+    virtual void onMaybeRemovedFromTree(RenderNode* node) {}
+protected:
+    ~TreeObserver() {}
+};
+
 // This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
 class TreeInfo {
     PREVENT_COPY_AND_ASSIGN(TreeInfo);
@@ -86,6 +98,10 @@
 #endif
     ErrorHandler* errorHandler = nullptr;
 
+    // Optional, may be nullptr. Used to allow things to observe interesting
+    // tree state changes
+    TreeObserver* observer = nullptr;
+
     // Frame number for use with synchronized surfaceview position updating
     int64_t frameNumber = -1;
     int32_t windowInsetLeft = 0;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index d35f764..adfe45c 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
 #include "VectorDrawable.h"
 
 #include "PathParser.h"
+#include "SkColorFilter.h"
 #include "SkImageInfo.h"
 #include "SkShader.h"
 #include <utils/Log.h>
@@ -32,41 +33,36 @@
 
 const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
 
-void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY,
+        bool useStagingData) {
     float matrixScale = getMatrixScale(groupStackedMatrix);
     if (matrixScale == 0) {
         // When either x or y is scaled to 0, we don't need to draw anything.
         return;
     }
 
-    const SkPath updatedPath = getUpdatedPath();
     SkMatrix pathMatrix(groupStackedMatrix);
     pathMatrix.postScale(scaleX, scaleY);
 
     //TODO: try apply the path matrix to the canvas instead of creating a new path.
     SkPath renderPath;
     renderPath.reset();
-    renderPath.addPath(updatedPath, pathMatrix);
+
+    if (useStagingData) {
+        SkPath tmpPath;
+        getStagingPath(&tmpPath);
+        renderPath.addPath(tmpPath, pathMatrix);
+    } else {
+        renderPath.addPath(getUpdatedPath(), pathMatrix);
+    }
 
     float minScale = fmin(scaleX, scaleY);
     float strokeScale = minScale * matrixScale;
-    drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
-}
-
-void Path::setPathData(const Data& data) {
-    if (mData == data) {
-        return;
-    }
-    // Updates the path data. Note that we don't generate a new Skia path right away
-    // because there are cases where the animation is changing the path data, but the view
-    // that hosts the VD has gone off screen, in which case we won't even draw. So we
-    // postpone the Skia path generation to the draw time.
-    mData = data;
-    mSkPathDirty = true;
+    drawPath(outCanvas, renderPath, strokeScale, pathMatrix, useStagingData);
 }
 
 void Path::dump() {
-    ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+    ALOGD("Path: %s has %zu points", mName.c_str(), mProperties.getData().points.size());
 }
 
 float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
@@ -95,213 +91,215 @@
     }
     return matrixScale;
 }
+
+// Called from UI thread during the initial setup/theme change.
 Path::Path(const char* pathStr, size_t strLength) {
     PathParser::ParseResult result;
-    PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
-    if (!result.failureOccurred) {
-        VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-    }
-}
-
-Path::Path(const Data& data) {
-    mData = data;
-    // Now we need to construct a path
-    VectorDrawableUtils::verbsToPath(&mSkPath, data);
+    Data data;
+    PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+    mStagingProperties.setData(data);
 }
 
 Path::Path(const Path& path) : Node(path) {
-    mData = path.mData;
-    VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-bool Path::canMorph(const Data& morphTo) {
-    return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool Path::canMorph(const Path& path) {
-    return canMorph(path.mData);
+    mStagingProperties.syncProperties(path.mStagingProperties);
 }
 
 const SkPath& Path::getUpdatedPath() {
     if (mSkPathDirty) {
         mSkPath.reset();
-        VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+        VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
         mSkPathDirty = false;
     }
     return mSkPath;
 }
 
-void Path::setPath(const char* pathStr, size_t strLength) {
-    PathParser::ParseResult result;
-    mSkPathDirty = true;
-    PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+void Path::getStagingPath(SkPath* outPath) {
+    outPath->reset();
+    VectorDrawableUtils::verbsToPath(outPath, mStagingProperties.getData());
+}
+
+void Path::syncProperties() {
+    if (mStagingPropertiesDirty) {
+        mProperties.syncProperties(mStagingProperties);
+    } else {
+        mStagingProperties.syncProperties(mProperties);
+    }
+    mStagingPropertiesDirty = false;
 }
 
 FullPath::FullPath(const FullPath& path) : Path(path) {
-    mProperties = path.mProperties;
-    SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
-    SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
+    mStagingProperties.syncProperties(path.mStagingProperties);
+}
+
+static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart, float trimPathEnd,
+        float trimPathOffset) {
+    if (trimPathStart == 0.0f && trimPathEnd == 1.0f) {
+        *outPath = inPath;
+        return;
+    }
+    outPath->reset();
+    if (trimPathStart == trimPathEnd) {
+        // Trimmed path should be empty.
+        return;
+    }
+    SkPathMeasure measure(inPath, false);
+    float len = SkScalarToFloat(measure.getLength());
+    float start = len * fmod((trimPathStart + trimPathOffset), 1.0f);
+    float end = len * fmod((trimPathEnd + trimPathOffset), 1.0f);
+
+    if (start > end) {
+        measure.getSegment(start, len, outPath, true);
+        if (end > 0) {
+            measure.getSegment(0, end, outPath, true);
+        }
+    } else {
+        measure.getSegment(start, end, outPath, true);
+    }
 }
 
 const SkPath& FullPath::getUpdatedPath() {
-    if (!mSkPathDirty && !mTrimDirty) {
+    if (!mSkPathDirty && !mProperties.mTrimDirty) {
         return mTrimmedSkPath;
     }
     Path::getUpdatedPath();
-    if (mProperties.trimPathStart != 0.0f || mProperties.trimPathEnd != 1.0f) {
-        applyTrim();
+    if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
+        mProperties.mTrimDirty = false;
+        applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
+                mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
         return mTrimmedSkPath;
     } else {
         return mSkPath;
     }
 }
 
-void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
-        SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
-        float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
-        int fillType) {
-    mProperties.strokeWidth = strokeWidth;
-    mProperties.strokeColor = strokeColor;
-    mProperties.strokeAlpha = strokeAlpha;
-    mProperties.fillColor = fillColor;
-    mProperties.fillAlpha = fillAlpha;
-    mProperties.strokeMiterLimit = strokeMiterLimit;
-    mProperties.strokeLineCap = strokeLineCap;
-    mProperties.strokeLineJoin = strokeLineJoin;
-    mProperties.fillType = fillType;
-
-    // If any trim property changes, mark trim dirty and update the trim path
-    setTrimPathStart(trimPathStart);
-    setTrimPathEnd(trimPathEnd);
-    setTrimPathOffset(trimPathOffset);
+void FullPath::getStagingPath(SkPath* outPath) {
+    Path::getStagingPath(outPath);
+    SkPath inPath = *outPath;
+    applyTrim(outPath, inPath, mStagingProperties.getTrimPathStart(),
+            mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
 }
 
+void FullPath::dump() {
+    Path::dump();
+    ALOGD("stroke width, color, alpha: %f, %d, %f, fill color, alpha: %d, %f",
+            mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
+            mProperties.getFillColor(), mProperties.getFillAlpha());
+}
+
+
 inline SkColor applyAlpha(SkColor color, float alpha) {
     int alphaBytes = SkColorGetA(color);
     return SkColorSetA(color, alphaBytes * alpha);
 }
 
 void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeScale,
-                        const SkMatrix& matrix){
+                        const SkMatrix& matrix, bool useStagingData){
+    const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
+
     // Draw path's fill, if fill color or gradient is valid
     bool needsFill = false;
-    if (mFillGradient != nullptr) {
-        mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.fillAlpha));
-        SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
-        mPaint.setShader(newShader);
+    SkPaint paint;
+    if (properties.getFillGradient() != nullptr) {
+        paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
+        SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
+        paint.setShader(newShader);
         needsFill = true;
-    } else if (mProperties.fillColor != SK_ColorTRANSPARENT) {
-        mPaint.setColor(applyAlpha(mProperties.fillColor, mProperties.fillAlpha));
+    } else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
+        paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
         needsFill = true;
     }
 
     if (needsFill) {
-        mPaint.setStyle(SkPaint::Style::kFill_Style);
-        mPaint.setAntiAlias(true);
-        SkPath::FillType ft = static_cast<SkPath::FillType>(mProperties.fillType);
+        paint.setStyle(SkPaint::Style::kFill_Style);
+        paint.setAntiAlias(true);
+        SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
         renderPath.setFillType(ft);
-        outCanvas->drawPath(renderPath, mPaint);
+        outCanvas->drawPath(renderPath, paint);
     }
 
-    // Draw path's stroke, if stroke color or gradient is valid
+    // Draw path's stroke, if stroke color or Gradient is valid
     bool needsStroke = false;
-    if (mStrokeGradient != nullptr) {
-        mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.strokeAlpha));
-        SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
-        mPaint.setShader(newShader);
+    if (properties.getStrokeGradient() != nullptr) {
+        paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
+        SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
+        paint.setShader(newShader);
         needsStroke = true;
-    } else if (mProperties.strokeColor != SK_ColorTRANSPARENT) {
-        mPaint.setColor(applyAlpha(mProperties.strokeColor, mProperties.strokeAlpha));
+    } else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
+        paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
         needsStroke = true;
     }
     if (needsStroke) {
-        mPaint.setStyle(SkPaint::Style::kStroke_Style);
-        mPaint.setAntiAlias(true);
-        mPaint.setStrokeJoin(SkPaint::Join(mProperties.strokeLineJoin));
-        mPaint.setStrokeCap(SkPaint::Cap(mProperties.strokeLineCap));
-        mPaint.setStrokeMiter(mProperties.strokeMiterLimit);
-        mPaint.setStrokeWidth(mProperties.strokeWidth * strokeScale);
-        outCanvas->drawPath(renderPath, mPaint);
+        paint.setStyle(SkPaint::Style::kStroke_Style);
+        paint.setAntiAlias(true);
+        paint.setStrokeJoin(SkPaint::Join(properties.getStrokeLineJoin()));
+        paint.setStrokeCap(SkPaint::Cap(properties.getStrokeLineCap()));
+        paint.setStrokeMiter(properties.getStrokeMiterLimit());
+        paint.setStrokeWidth(properties.getStrokeWidth() * strokeScale);
+        outCanvas->drawPath(renderPath, paint);
     }
 }
 
-/**
- * Applies trimming to the specified path.
- */
-void FullPath::applyTrim() {
-    if (mProperties.trimPathStart == 0.0f && mProperties.trimPathEnd == 1.0f) {
-        // No trimming necessary.
-        return;
-    }
-    mTrimDirty = false;
-    mTrimmedSkPath.reset();
-    if (mProperties.trimPathStart == mProperties.trimPathEnd) {
-        // Trimmed path should be empty.
-        return;
-    }
-    SkPathMeasure measure(mSkPath, false);
-    float len = SkScalarToFloat(measure.getLength());
-    float start = len * fmod((mProperties.trimPathStart + mProperties.trimPathOffset), 1.0f);
-    float end = len * fmod((mProperties.trimPathEnd + mProperties.trimPathOffset), 1.0f);
+void FullPath::syncProperties() {
+    Path::syncProperties();
 
-    if (start > end) {
-        measure.getSegment(start, len, &mTrimmedSkPath, true);
-        if (end > 0) {
-            measure.getSegment(0, end, &mTrimmedSkPath, true);
-        }
+    if (mStagingPropertiesDirty) {
+        mProperties.syncProperties(mStagingProperties);
     } else {
-        measure.getSegment(start, end, &mTrimmedSkPath, true);
+        // Update staging property with property values from animation.
+        mStagingProperties.syncProperties(mProperties);
     }
+    mStagingPropertiesDirty = false;
 }
 
-REQUIRE_COMPATIBLE_LAYOUT(FullPath::Properties);
+REQUIRE_COMPATIBLE_LAYOUT(FullPath::FullPathProperties::PrimitiveFields);
 
 static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
 static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
 
-bool FullPath::getProperties(int8_t* outProperties, int length) {
-    int propertyDataSize = sizeof(Properties);
+bool FullPath::FullPathProperties::copyProperties(int8_t* outProperties, int length) const {
+    int propertyDataSize = sizeof(FullPathProperties::PrimitiveFields);
     if (length != propertyDataSize) {
         LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
                 propertyDataSize, length);
         return false;
     }
-    Properties* out = reinterpret_cast<Properties*>(outProperties);
-    *out = mProperties;
+
+    PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+    *out = mPrimitiveFields;
     return true;
 }
 
-void FullPath::setColorPropertyValue(int propertyId, int32_t value) {
+void FullPath::FullPathProperties::setColorPropertyValue(int propertyId, int32_t value) {
     Property currentProperty = static_cast<Property>(propertyId);
-    if (currentProperty == Property::StrokeColor) {
-        mProperties.strokeColor = value;
-    } else if (currentProperty == Property::FillColor) {
-        mProperties.fillColor = value;
+    if (currentProperty == Property::strokeColor) {
+        setStrokeColor(value);
+    } else if (currentProperty == Property::fillColor) {
+        setFillColor(value);
     } else {
-        LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property with id: %d",
-                propertyId);
+        LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property"
+                " with id: %d", propertyId);
     }
 }
 
-void FullPath::setPropertyValue(int propertyId, float value) {
+void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value) {
     Property property = static_cast<Property>(propertyId);
     switch (property) {
-    case Property::StrokeWidth:
+    case Property::strokeWidth:
         setStrokeWidth(value);
         break;
-    case Property::StrokeAlpha:
+    case Property::strokeAlpha:
         setStrokeAlpha(value);
         break;
-    case Property::FillAlpha:
+    case Property::fillAlpha:
         setFillAlpha(value);
         break;
-    case Property::TrimPathStart:
+    case Property::trimPathStart:
         setTrimPathStart(value);
         break;
-    case Property::TrimPathEnd:
+    case Property::trimPathEnd:
         setTrimPathEnd(value);
         break;
-    case Property::TrimPathOffset:
+    case Property::trimPathOffset:
         setTrimPathOffset(value);
         break;
     default:
@@ -311,16 +309,16 @@
 }
 
 void ClipPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath,
-        float strokeScale, const SkMatrix& matrix){
+        float strokeScale, const SkMatrix& matrix, bool useStagingData){
     outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
 }
 
 Group::Group(const Group& group) : Node(group) {
-    mProperties = group.mProperties;
+    mStagingProperties.syncProperties(group.mStagingProperties);
 }
 
 void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
-        float scaleY) {
+        float scaleY, bool useStagingData) {
     // TODO: Try apply the matrix to the canvas instead of passing it down the tree
 
     // Calculate current group's matrix by preConcat the parent's and
@@ -328,14 +326,15 @@
     // Basically the Mfinal = Mviewport * M0 * M1 * M2;
     // Mi the local matrix at level i of the group tree.
     SkMatrix stackedMatrix;
-    getLocalMatrix(&stackedMatrix);
+    const GroupProperties& prop = useStagingData ? mStagingProperties : mProperties;
+    getLocalMatrix(&stackedMatrix, prop);
     stackedMatrix.postConcat(currentMatrix);
 
     // Save the current clip information, which is local to this group.
     outCanvas->save();
     // Draw the group tree in the same order as the XML file.
     for (auto& child : mChildren) {
-        child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+        child->draw(outCanvas, stackedMatrix, scaleX, scaleY, useStagingData);
     }
     // Restore the previous clip information.
     outCanvas->restore();
@@ -343,96 +342,106 @@
 
 void Group::dump() {
     ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+    ALOGD("Group translateX, Y : %f, %f, scaleX, Y: %f, %f", mProperties.getTranslateX(),
+            mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
     for (size_t i = 0; i < mChildren.size(); i++) {
         mChildren[i]->dump();
     }
 }
 
-void Group::updateLocalMatrix(float rotate, float pivotX, float pivotY,
-        float scaleX, float scaleY, float translateX, float translateY) {
-    setRotation(rotate);
-    setPivotX(pivotX);
-    setPivotY(pivotY);
-    setScaleX(scaleX);
-    setScaleY(scaleY);
-    setTranslateX(translateX);
-    setTranslateY(translateY);
+void Group::syncProperties() {
+    // Copy over the dirty staging properties
+    if (mStagingPropertiesDirty) {
+        mProperties.syncProperties(mStagingProperties);
+    } else {
+        mStagingProperties.syncProperties(mProperties);
+    }
+    mStagingPropertiesDirty = false;
+    for (auto& child : mChildren) {
+        child->syncProperties();
+    }
 }
 
-void Group::getLocalMatrix(SkMatrix* outMatrix) {
+void Group::getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties) {
     outMatrix->reset();
     // TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
     // translating to pivot for rotating and scaling, then translating back.
-    outMatrix->postTranslate(-mProperties.pivotX, -mProperties.pivotY);
-    outMatrix->postScale(mProperties.scaleX, mProperties.scaleY);
-    outMatrix->postRotate(mProperties.rotate, 0, 0);
-    outMatrix->postTranslate(mProperties.translateX + mProperties.pivotX,
-            mProperties.translateY + mProperties.pivotY);
+    outMatrix->postTranslate(-properties.getPivotX(), -properties.getPivotY());
+    outMatrix->postScale(properties.getScaleX(), properties.getScaleY());
+    outMatrix->postRotate(properties.getRotation(), 0, 0);
+    outMatrix->postTranslate(properties.getTranslateX() + properties.getPivotX(),
+            properties.getTranslateY() + properties.getPivotY());
 }
 
 void Group::addChild(Node* child) {
     mChildren.emplace_back(child);
+    if (mPropertyChangedListener != nullptr) {
+        child->setPropertyChangedListener(mPropertyChangedListener);
+    }
 }
 
-bool Group::getProperties(float* outProperties, int length) {
-    int propertyCount = static_cast<int>(Property::Count);
+bool Group::GroupProperties::copyProperties(float* outProperties, int length) const {
+    int propertyCount = static_cast<int>(Property::count);
     if (length != propertyCount) {
         LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
                 propertyCount, length);
         return false;
     }
-    Properties* out = reinterpret_cast<Properties*>(outProperties);
-    *out = mProperties;
+
+    PrimitiveFields* out = reinterpret_cast<PrimitiveFields*>(outProperties);
+    *out = mPrimitiveFields;
     return true;
 }
 
 // TODO: Consider animating the properties as float pointers
-float Group::getPropertyValue(int propertyId) const {
+// Called on render thread
+float Group::GroupProperties::getPropertyValue(int propertyId) const {
     Property currentProperty = static_cast<Property>(propertyId);
     switch (currentProperty) {
-    case Property::Rotate:
-        return mProperties.rotate;
-    case Property::PivotX:
-        return mProperties.pivotX;
-    case Property::PivotY:
-        return mProperties.pivotY;
-    case Property::ScaleX:
-        return mProperties.scaleX;
-    case Property::ScaleY:
-        return mProperties.scaleY;
-    case Property::TranslateX:
-        return mProperties.translateX;
-    case Property::TranslateY:
-        return mProperties.translateY;
+    case Property::rotate:
+        return getRotation();
+    case Property::pivotX:
+        return getPivotX();
+    case Property::pivotY:
+        return getPivotY();
+    case Property::scaleX:
+        return getScaleX();
+    case Property::scaleY:
+        return getScaleY();
+    case Property::translateX:
+        return getTranslateX();
+    case Property::translateY:
+        return getTranslateY();
     default:
         LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
         return 0;
     }
 }
 
-void Group::setPropertyValue(int propertyId, float value) {
+// Called on render thread
+void Group::GroupProperties::setPropertyValue(int propertyId, float value) {
     Property currentProperty = static_cast<Property>(propertyId);
     switch (currentProperty) {
-    case Property::Rotate:
-        mProperties.rotate = value;
+    case Property::rotate:
+        setRotation(value);
         break;
-    case Property::PivotX:
-        mProperties.pivotX = value;
+    case Property::pivotX:
+        setPivotX(value);
         break;
-    case Property::PivotY:
-        mProperties.pivotY = value;
+    case Property::pivotY:
+        setPivotY(value);
         break;
-    case Property::ScaleX:
-        mProperties.scaleX = value;
+    case Property::scaleX:
+        setScaleX(value);
         break;
-    case Property::ScaleY:
-        mProperties.scaleY = value;
+    case Property::scaleY:
+        setScaleY(value);
         break;
-    case Property::TranslateX:
-        mProperties.translateX = value;
+    case Property::translateX:
+        setTranslateX(value);
         break;
-    case Property::TranslateY:
-        mProperties.translateY = value;
+    case Property::translateY:
+        setTranslateY(value);
         break;
     default:
         LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
@@ -440,7 +449,11 @@
 }
 
 bool Group::isValidProperty(int propertyId) {
-    return propertyId >= 0 && propertyId < static_cast<int>(Property::Count);
+    return GroupProperties::isValidProperty(propertyId);
+}
+
+bool Group::GroupProperties::isValidProperty(int propertyId) {
+    return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
 }
 
 void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
@@ -449,18 +462,18 @@
     // avoid blurry scaling, we have to draw into a bitmap with exact pixel
     // size first. This bitmap size is determined by the bounds and the
     // canvas scale.
-    outCanvas->getMatrix(&mCanvasMatrix);
-    mBounds = bounds;
+    SkMatrix canvasMatrix;
+    outCanvas->getMatrix(&canvasMatrix);
     float canvasScaleX = 1.0f;
     float canvasScaleY = 1.0f;
-    if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
+    if (canvasMatrix.getSkewX() == 0 && canvasMatrix.getSkewY() == 0) {
         // Only use the scale value when there's no skew or rotation in the canvas matrix.
         // TODO: Add a cts test for drawing VD on a canvas with negative scaling factors.
-        canvasScaleX = fabs(mCanvasMatrix.getScaleX());
-        canvasScaleY = fabs(mCanvasMatrix.getScaleY());
+        canvasScaleX = fabs(canvasMatrix.getScaleX());
+        canvasScaleY = fabs(canvasMatrix.getScaleY());
     }
-    int scaledWidth = (int) (mBounds.width() * canvasScaleX);
-    int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+    int scaledWidth = (int) (bounds.width() * canvasScaleX);
+    int scaledHeight = (int) (bounds.height() * canvasScaleY);
     scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
     scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
 
@@ -468,63 +481,105 @@
         return;
     }
 
-    mPaint.setColorFilter(colorFilter);
-
+    mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
     int saveCount = outCanvas->save(SaveFlags::MatrixClip);
-    outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+    outCanvas->translate(bounds.fLeft, bounds.fTop);
 
     // Handle RTL mirroring.
     if (needsMirroring) {
-        outCanvas->translate(mBounds.width(), 0);
+        outCanvas->translate(bounds.width(), 0);
         outCanvas->scale(-1.0f, 1.0f);
     }
+    mStagingProperties.setColorFilter(colorFilter);
 
     // At this point, canvas has been translated to the right position.
     // And we use this bound for the destination rect for the drawBitmap, so
     // we offset to (0, 0);
-    mBounds.offsetTo(0, 0);
-    createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
-
+    SkRect tmpBounds = bounds;
+    tmpBounds.offsetTo(0, 0);
+    mStagingProperties.setBounds(tmpBounds);
     outCanvas->drawVectorDrawable(this);
-
     outCanvas->restoreToCount(saveCount);
 }
 
-SkPaint* Tree::getPaint() {
-    SkPaint* paint;
-    if (mRootAlpha == 1.0f && mPaint.getColorFilter() == NULL) {
-        paint = NULL;
-    } else {
-        mPaint.setFilterQuality(kLow_SkFilterQuality);
-        mPaint.setAlpha(mRootAlpha * 255);
-        paint = &mPaint;
+void Tree::drawStaging(Canvas* outCanvas) {
+    bool redrawNeeded = allocateBitmapIfNeeded(&mStagingCache.bitmap,
+            mStagingProperties.getScaledWidth(), mStagingProperties.getScaledHeight());
+    // draw bitmap cache
+    if (redrawNeeded || mStagingCache.dirty) {
+        updateBitmapCache(&mStagingCache.bitmap, true);
+        mStagingCache.dirty = false;
     }
-    return paint;
+
+    SkPaint tmpPaint;
+    SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
+    outCanvas->drawBitmap(mStagingCache.bitmap, 0, 0,
+            mStagingCache.bitmap.width(), mStagingCache.bitmap.height(),
+            mStagingProperties.getBounds().left(), mStagingProperties.getBounds().top(),
+            mStagingProperties.getBounds().right(), mStagingProperties.getBounds().bottom(), paint);
+}
+
+SkPaint* Tree::getPaint() {
+    return updatePaint(&mPaint, &mProperties);
+}
+
+// Update the given paint with alpha and color filter. Return nullptr if no color filter is
+// specified and root alpha is 1. Otherwise, return updated paint.
+SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
+    if (prop->getRootAlpha() == 1.0f && prop->getColorFilter() == nullptr) {
+        return nullptr;
+    } else {
+        outPaint->setColorFilter(mStagingProperties.getColorFilter());
+        outPaint->setFilterQuality(kLow_SkFilterQuality);
+        outPaint->setAlpha(prop->getRootAlpha() * 255);
+        return outPaint;
+    }
 }
 
 const SkBitmap& Tree::getBitmapUpdateIfDirty() {
-    mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
-    SkCanvas outCanvas(mCachedBitmap);
-    float scaleX = (float) mCachedBitmap.width() / mViewportWidth;
-    float scaleY = (float) mCachedBitmap.height() / mViewportHeight;
-    mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY);
-    mCacheDirty = false;
-    return mCachedBitmap;
+    bool redrawNeeded = allocateBitmapIfNeeded(&mCache.bitmap, mProperties.getScaledWidth(),
+            mProperties.getScaledHeight());
+    if (redrawNeeded || mCache.dirty) {
+        updateBitmapCache(&mCache.bitmap, false);
+        mCache.dirty = false;
+    }
+    return mCache.bitmap;
 }
 
-void Tree::createCachedBitmapIfNeeded(int width, int height) {
-    if (!canReuseBitmap(width, height)) {
+void Tree::updateBitmapCache(SkBitmap* outCache, bool useStagingData) {
+    outCache->eraseColor(SK_ColorTRANSPARENT);
+    SkCanvas outCanvas(*outCache);
+    float viewportWidth = useStagingData ?
+            mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
+    float viewportHeight = useStagingData ?
+            mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
+    float scaleX = outCache->width() / viewportWidth;
+    float scaleY = outCache->height() / viewportHeight;
+    mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY, useStagingData);
+}
+
+bool Tree::allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height) {
+    if (!canReuseBitmap(*outCache, width, height)) {
         SkImageInfo info = SkImageInfo::Make(width, height,
                 kN32_SkColorType, kPremul_SkAlphaType);
-        mCachedBitmap.setInfo(info);
+        outCache->setInfo(info);
         // TODO: Count the bitmap cache against app's java heap
-        mCachedBitmap.allocPixels(info);
-        mCacheDirty = true;
+        outCache->allocPixels(info);
+        return true;
     }
+    return false;
 }
 
-bool Tree::canReuseBitmap(int width, int height) {
-    return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+bool Tree::canReuseBitmap(const SkBitmap& bitmap, int width, int height) {
+    return width == bitmap.width() && height == bitmap.height();
+}
+
+void Tree::onPropertyChanged(TreeProperties* prop) {
+    if (prop == &mStagingProperties) {
+        mStagingCache.dirty = true;
+    } else {
+        mCache.dirty = true;
+    }
 }
 
 }; // namespace VectorDrawable
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 7a45bf5..e4c7ed7 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -18,9 +18,11 @@
 #define ANDROID_HWUI_VPATH_H
 
 #include "hwui/Canvas.h"
+#include "DisplayList.h"
 
 #include <SkBitmap.h>
 #include <SkColor.h>
+#include <SkColorFilter.h>
 #include <SkCanvas.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
@@ -38,8 +40,11 @@
 namespace uirenderer {
 
 namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
+#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
 #define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
+#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+    onPropertyChanged(); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
 
 /* A VectorDrawable is composed of a tree of nodes.
  * Each node can be a group node, or a path.
@@ -52,22 +57,65 @@
  *          /     \             |
  *         Path   Path         Path
  *
+ * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
+ * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
+ * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
+ * Each cache has their own generation id to track whether they are up to date with the latest
+ * change in the tree.
+ *
+ * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
+ * all the properties, and viewport change, etc.) are only modifying the staging properties. The
+ * staging properties will then be marked dirty and will be pushed over to render thread properties
+ * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
+ * staging properties with render thread properties to reflect the latest animation value.
+ *
  */
+
+class PropertyChangedListener {
+public:
+    PropertyChangedListener(bool* dirty, bool* stagingDirty)
+            : mDirty(dirty), mStagingDirty(stagingDirty) {}
+    void onPropertyChanged() {
+            *mDirty = true;
+    }
+    void onStagingPropertyChanged() {
+            *mStagingDirty = true;
+    }
+private:
+    bool* mDirty;
+    bool* mStagingDirty;
+};
+
 class ANDROID_API Node {
 public:
+    class Properties {
+    public:
+        Properties(Node* node) : mNode(node) {}
+        inline void onPropertyChanged() {
+            mNode->onPropertyChanged(this);
+        }
+    private:
+        Node* mNode;
+    };
     Node(const Node& node) {
         mName = node.mName;
     }
     Node() {}
     virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
-            float scaleX, float scaleY) = 0;
+            float scaleX, float scaleY, bool useStagingData) = 0;
     virtual void dump() = 0;
     void setName(const char* name) {
         mName = name;
     }
+    virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
+        mPropertyChangedListener = listener;
+    }
+    virtual void onPropertyChanged(Properties* properties) = 0;
     virtual ~Node(){}
+    virtual void syncProperties() = 0;
 protected:
     std::string mName;
+    PropertyChangedListener* mPropertyChangedListener = nullptr;
 };
 
 class ANDROID_API Path : public Node {
@@ -81,150 +129,267 @@
                     && points == data.points;
         }
     };
-    Path(const Data& nodes);
+
+    class PathProperties : public Properties {
+    public:
+        PathProperties(Node* node) : Properties(node) {}
+        void syncProperties(const PathProperties& prop) {
+            mData = prop.mData;
+            onPropertyChanged();
+        }
+        void setData(const Data& data) {
+            // Updates the path data. Note that we don't generate a new Skia path right away
+            // because there are cases where the animation is changing the path data, but the view
+            // that hosts the VD has gone off screen, in which case we won't even draw. So we
+            // postpone the Skia path generation to the draw time.
+            if (data == mData) {
+                return;
+            }
+            mData = data;
+            onPropertyChanged();
+
+        }
+        const Data& getData() const {
+            return mData;
+        }
+    private:
+        Data mData;
+    };
+
     Path(const Path& path);
     Path(const char* path, size_t strLength);
     Path() {}
+
     void dump() override;
-    bool canMorph(const Data& path);
-    bool canMorph(const Path& path);
     void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
-            float scaleX, float scaleY) override;
-    void setPath(const char* path, size_t strLength);
-    void setPathData(const Data& data);
+            float scaleX, float scaleY, bool useStagingData) override;
     static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+    virtual void syncProperties() override;
+    virtual void onPropertyChanged(Properties* prop) override {
+        if (prop == &mStagingProperties) {
+            mStagingPropertiesDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onStagingPropertyChanged();
+            }
+        } else if (prop == &mProperties){
+            mSkPathDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onPropertyChanged();
+            }
+        }
+    }
+    PathProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const PathProperties* stagingProperties() { return &mStagingProperties; }
+
+    // This should only be called from animations on RT
+    PathProperties* mutateProperties() { return &mProperties; }
 
 protected:
     virtual const SkPath& getUpdatedPath();
+    virtual void getStagingPath(SkPath* outPath);
     virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
-            float strokeScale, const SkMatrix& matrix) = 0;
-    Data mData;
-    SkPath mSkPath;
+            float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
+
+    // Internal data, render thread only.
     bool mSkPathDirty = true;
+    SkPath mSkPath;
+
+private:
+    PathProperties mProperties = PathProperties(this);
+    PathProperties mStagingProperties = PathProperties(this);
+    bool mStagingPropertiesDirty = true;
 };
 
 class ANDROID_API FullPath: public Path {
 public:
+    class FullPathProperties : public Properties {
+    public:
+        struct PrimitiveFields {
+            float strokeWidth = 0;
+            SkColor strokeColor = SK_ColorTRANSPARENT;
+            float strokeAlpha = 1;
+            SkColor fillColor = SK_ColorTRANSPARENT;
+            float fillAlpha = 1;
+            float trimPathStart = 0;
+            float trimPathEnd = 1;
+            float trimPathOffset = 0;
+            int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
+            int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
+            float strokeMiterLimit = 4;
+            int fillType = 0; /* non-zero or kWinding_FillType in Skia */
+        };
+        FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
+        void syncProperties(const FullPathProperties& prop) {
+            mPrimitiveFields = prop.mPrimitiveFields;
+            mTrimDirty = true;
+            fillGradient.reset(prop.fillGradient);
+            strokeGradient.reset(prop.strokeGradient);
+            onPropertyChanged();
+        }
+        void setFillGradient(SkShader* gradient) {
+            if(fillGradient != gradient){
+                fillGradient.reset(gradient);
+                onPropertyChanged();
+            }
+        }
+        void setStrokeGradient(SkShader* gradient) {
+            if(strokeGradient != gradient){
+                strokeGradient.reset(gradient);
+                onPropertyChanged();
+            }
+        }
+        SkShader* getFillGradient() const {
+            return fillGradient;
+        }
+        SkShader* getStrokeGradient() const {
+            return strokeGradient;
+        }
+        float getStrokeWidth() const{
+            return mPrimitiveFields.strokeWidth;
+        }
+        void setStrokeWidth(float strokeWidth) {
+            VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+        }
+        SkColor getStrokeColor() const{
+            return mPrimitiveFields.strokeColor;
+        }
+        void setStrokeColor(SkColor strokeColor) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+        }
+        float getStrokeAlpha() const{
+            return mPrimitiveFields.strokeAlpha;
+        }
+        void setStrokeAlpha(float strokeAlpha) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+        }
+        SkColor getFillColor() const {
+            return mPrimitiveFields.fillColor;
+        }
+        void setFillColor(SkColor fillColor) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+        }
+        float getFillAlpha() const{
+            return mPrimitiveFields.fillAlpha;
+        }
+        void setFillAlpha(float fillAlpha) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+        }
+        float getTrimPathStart() const{
+            return mPrimitiveFields.trimPathStart;
+        }
+        void setTrimPathStart(float trimPathStart) {
+            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+        }
+        float getTrimPathEnd() const{
+            return mPrimitiveFields.trimPathEnd;
+        }
+        void setTrimPathEnd(float trimPathEnd) {
+            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+        }
+        float getTrimPathOffset() const{
+            return mPrimitiveFields.trimPathOffset;
+        }
+        void setTrimPathOffset(float trimPathOffset) {
+            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+        }
 
-struct Properties {
-    float strokeWidth = 0;
-    SkColor strokeColor = SK_ColorTRANSPARENT;
-    float strokeAlpha = 1;
-    SkColor fillColor = SK_ColorTRANSPARENT;
-    float fillAlpha = 1;
-    float trimPathStart = 0;
-    float trimPathEnd = 1;
-    float trimPathOffset = 0;
-    int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
-    int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
-    float strokeMiterLimit = 4;
-    int fillType = 0; /* non-zero or kWinding_FillType in Skia */
-};
+        float getStrokeMiterLimit() const {
+            return mPrimitiveFields.strokeMiterLimit;
+        }
+        float getStrokeLineCap() const {
+            return mPrimitiveFields.strokeLineCap;
+        }
+        float getStrokeLineJoin() const {
+            return mPrimitiveFields.strokeLineJoin;
+        }
+        float getFillType() const {
+            return mPrimitiveFields.fillType;
+        }
+        bool copyProperties(int8_t* outProperties, int length) const;
+        void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
+                SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
+                float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
+                int fillType) {
+            mPrimitiveFields.strokeWidth = strokeWidth;
+            mPrimitiveFields.strokeColor = strokeColor;
+            mPrimitiveFields.strokeAlpha = strokeAlpha;
+            mPrimitiveFields.fillColor = fillColor;
+            mPrimitiveFields.fillAlpha = fillAlpha;
+            mPrimitiveFields.trimPathStart = trimPathStart;
+            mPrimitiveFields.trimPathEnd = trimPathEnd;
+            mPrimitiveFields.trimPathOffset = trimPathOffset;
+            mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
+            mPrimitiveFields.strokeLineCap = strokeLineCap;
+            mPrimitiveFields.strokeLineJoin = strokeLineJoin;
+            mPrimitiveFields.fillType = fillType;
+            mTrimDirty = true;
+            onPropertyChanged();
+        }
+        // Set property values during animation
+        void setColorPropertyValue(int propertyId, int32_t value);
+        void setPropertyValue(int propertyId, float value);
+        bool mTrimDirty;
+    private:
+        enum class Property {
+            strokeWidth = 0,
+            strokeColor,
+            strokeAlpha,
+            fillColor,
+            fillAlpha,
+            trimPathStart,
+            trimPathEnd,
+            trimPathOffset,
+            strokeLineCap,
+            strokeLineJoin,
+            strokeMiterLimit,
+            fillType,
+            count,
+        };
+        PrimitiveFields mPrimitiveFields;
+        SkAutoTUnref<SkShader> fillGradient;
+        SkAutoTUnref<SkShader> strokeGradient;
+    };
 
+    // Called from UI thread
     FullPath(const FullPath& path); // for cloning
     FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
     FullPath() : Path() {}
-    FullPath(const Data& nodes) : Path(nodes) {}
+    void dump() override;
+    FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const FullPathProperties* stagingProperties() { return &mStagingProperties; }
 
-    ~FullPath() {
-        SkSafeUnref(mFillGradient);
-        SkSafeUnref(mStrokeGradient);
-    }
+    // This should only be called from animations on RT
+    FullPathProperties* mutateProperties() { return &mProperties; }
 
-    void updateProperties(float strokeWidth, SkColor strokeColor,
-            float strokeAlpha, SkColor fillColor, float fillAlpha,
-            float trimPathStart, float trimPathEnd, float trimPathOffset,
-            float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, int fillType);
-    // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
-    float getStrokeWidth() {
-        return mProperties.strokeWidth;
+    virtual void syncProperties() override;
+    virtual void onPropertyChanged(Properties* properties) override {
+        Path::onPropertyChanged(properties);
+        if (properties == &mStagingProperties) {
+            mStagingPropertiesDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onStagingPropertyChanged();
+            }
+        } else if (properties == &mProperties) {
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onPropertyChanged();
+            }
+        }
     }
-    void setStrokeWidth(float strokeWidth) {
-        mProperties.strokeWidth = strokeWidth;
-    }
-    SkColor getStrokeColor() {
-        return mProperties.strokeColor;
-    }
-    void setStrokeColor(SkColor strokeColor) {
-        mProperties.strokeColor = strokeColor;
-    }
-    float getStrokeAlpha() {
-        return mProperties.strokeAlpha;
-    }
-    void setStrokeAlpha(float strokeAlpha) {
-        mProperties.strokeAlpha = strokeAlpha;
-    }
-    SkColor getFillColor() {
-        return mProperties.fillColor;
-    }
-    void setFillColor(SkColor fillColor) {
-        mProperties.fillColor = fillColor;
-    }
-    float getFillAlpha() {
-        return mProperties.fillAlpha;
-    }
-    void setFillAlpha(float fillAlpha) {
-        mProperties.fillAlpha = fillAlpha;
-    }
-    float getTrimPathStart() {
-        return mProperties.trimPathStart;
-    }
-    void setTrimPathStart(float trimPathStart) {
-        VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
-    }
-    float getTrimPathEnd() {
-        return mProperties.trimPathEnd;
-    }
-    void setTrimPathEnd(float trimPathEnd) {
-        VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
-    }
-    float getTrimPathOffset() {
-        return mProperties.trimPathOffset;
-    }
-    void setTrimPathOffset(float trimPathOffset) {
-        VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
-    }
-    bool getProperties(int8_t* outProperties, int length);
-    void setColorPropertyValue(int propertyId, int32_t value);
-    void setPropertyValue(int propertyId, float value);
-
-    void setFillGradient(SkShader* fillGradient) {
-        SkRefCnt_SafeAssign(mFillGradient, fillGradient);
-    };
-    void setStrokeGradient(SkShader* strokeGradient) {
-        SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
-    };
-
 
 protected:
     const SkPath& getUpdatedPath() override;
+    void getStagingPath(SkPath* outPath) override;
     void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
-            float strokeScale, const SkMatrix& matrix) override;
-
+            float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
 private:
-    enum class Property {
-        StrokeWidth = 0,
-        StrokeColor,
-        StrokeAlpha,
-        FillColor,
-        FillAlpha,
-        TrimPathStart,
-        TrimPathEnd,
-        TrimPathOffset,
-        StrokeLineCap,
-        StrokeLineJoin,
-        StrokeMiterLimit,
-        FillType,
-        Count,
-    };
-    // Applies trimming to the specified path.
-    void applyTrim();
-    Properties mProperties;
-    bool mTrimDirty = true;
+
+    FullPathProperties mProperties = FullPathProperties(this);
+    FullPathProperties mStagingProperties = FullPathProperties(this);
+    bool mStagingPropertiesDirty = true;
+
+    // Intermediate data for drawing, render thread only
     SkPath mTrimmedSkPath;
-    SkPaint mPaint;
-    SkShader* mStrokeGradient = nullptr;
-    SkShader* mFillGradient = nullptr;
+
 };
 
 class ANDROID_API ClipPath: public Path {
@@ -232,143 +397,316 @@
     ClipPath(const ClipPath& path) : Path(path) {}
     ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
     ClipPath() : Path() {}
-    ClipPath(const Data& nodes) : Path(nodes) {}
 
 protected:
     void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
-            float strokeScale, const SkMatrix& matrix) override;
+            float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
 };
 
 class ANDROID_API Group: public Node {
 public:
-    struct Properties {
-        float rotate = 0;
-        float pivotX = 0;
-        float pivotY = 0;
-        float scaleX = 1;
-        float scaleY = 1;
-        float translateX = 0;
-        float translateY = 0;
+    class GroupProperties : public Properties {
+    public:
+        GroupProperties(Node* mNode) : Properties(mNode) {}
+        struct PrimitiveFields {
+            float rotate = 0;
+            float pivotX = 0;
+            float pivotY = 0;
+            float scaleX = 1;
+            float scaleY = 1;
+            float translateX = 0;
+            float translateY = 0;
+        } mPrimitiveFields;
+        void syncProperties(const GroupProperties& prop) {
+            mPrimitiveFields = prop.mPrimitiveFields;
+            onPropertyChanged();
+        }
+        float getRotation() const {
+            return mPrimitiveFields.rotate;
+        }
+        void setRotation(float rotation) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+        }
+        float getPivotX() const {
+            return mPrimitiveFields.pivotX;
+        }
+        void setPivotX(float pivotX) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+        }
+        float getPivotY() const {
+            return mPrimitiveFields.pivotY;
+        }
+        void setPivotY(float pivotY) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+        }
+        float getScaleX() const {
+            return mPrimitiveFields.scaleX;
+        }
+        void setScaleX(float scaleX) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+        }
+        float getScaleY() const {
+            return mPrimitiveFields.scaleY;
+        }
+        void setScaleY(float scaleY) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+        }
+        float getTranslateX() const {
+            return mPrimitiveFields.translateX;
+        }
+        void setTranslateX(float translateX) {
+            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+        }
+        float getTranslateY() const {
+            return mPrimitiveFields.translateY;
+        }
+        void setTranslateY(float translateY) {
+            VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+        }
+        void updateProperties(float rotate, float pivotX, float pivotY,
+                float scaleX, float scaleY, float translateX, float translateY) {
+            mPrimitiveFields.rotate = rotate;
+            mPrimitiveFields.pivotX = pivotX;
+            mPrimitiveFields.pivotY = pivotY;
+            mPrimitiveFields.scaleX = scaleX;
+            mPrimitiveFields.scaleY = scaleY;
+            mPrimitiveFields.translateX = translateX;
+            mPrimitiveFields.translateY = translateY;
+            onPropertyChanged();
+        }
+        void setPropertyValue(int propertyId, float value);
+        float getPropertyValue(int propertyId) const;
+        bool copyProperties(float* outProperties, int length) const;
+        static bool isValidProperty(int propertyId);
+    private:
+        enum class Property {
+            rotate = 0,
+            pivotX,
+            pivotY,
+            scaleX,
+            scaleY,
+            translateX,
+            translateY,
+            // Count of the properties, must be at the end.
+            count,
+        };
     };
+
     Group(const Group& group);
     Group() {}
-    float getRotation() {
-        return mProperties.rotate;
-    }
-    void setRotation(float rotation) {
-        mProperties.rotate = rotation;
-    }
-    float getPivotX() {
-        return mProperties.pivotX;
-    }
-    void setPivotX(float pivotX) {
-        mProperties.pivotX = pivotX;
-    }
-    float getPivotY() {
-        return mProperties.pivotY;
-    }
-    void setPivotY(float pivotY) {
-        mProperties.pivotY = pivotY;
-    }
-    float getScaleX() {
-        return mProperties.scaleX;
-    }
-    void setScaleX(float scaleX) {
-        mProperties.scaleX = scaleX;
-    }
-    float getScaleY() {
-        return mProperties.scaleY;
-    }
-    void setScaleY(float scaleY) {
-        mProperties.scaleY = scaleY;
-    }
-    float getTranslateX() {
-        return mProperties.translateX;
-    }
-    void setTranslateX(float translateX) {
-        mProperties.translateX = translateX;
-    }
-    float getTranslateY() {
-        return mProperties.translateY;
-    }
-    void setTranslateY(float translateY) {
-        mProperties.translateY = translateY;
-    }
-    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
-            float scaleX, float scaleY) override;
-    void updateLocalMatrix(float rotate, float pivotX, float pivotY,
-            float scaleX, float scaleY, float translateX, float translateY);
-    void getLocalMatrix(SkMatrix* outMatrix);
     void addChild(Node* child);
+    virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
+        Node::setPropertyChangedListener(listener);
+        for (auto& child : mChildren) {
+             child->setPropertyChangedListener(listener);
+        }
+    }
+    virtual void syncProperties() override;
+    GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const GroupProperties* stagingProperties() { return &mStagingProperties; }
+
+    // This should only be called from animations on RT
+    GroupProperties* mutateProperties() { return &mProperties; }
+
+    // Methods below could be called from either UI thread or Render Thread.
+    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
+            float scaleX, float scaleY, bool useStagingData) override;
+    void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
     void dump() override;
-    bool getProperties(float* outProperties, int length);
-    float getPropertyValue(int propertyId) const;
-    void setPropertyValue(int propertyId, float value);
     static bool isValidProperty(int propertyId);
 
+    virtual void onPropertyChanged(Properties* properties) override {
+        if (properties == &mStagingProperties) {
+            mStagingPropertiesDirty = true;
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onStagingPropertyChanged();
+            }
+        } else {
+            if (mPropertyChangedListener) {
+                mPropertyChangedListener->onPropertyChanged();
+            }
+        }
+    }
+
 private:
-    enum class Property {
-        Rotate = 0,
-        PivotX,
-        PivotY,
-        ScaleX,
-        ScaleY,
-        TranslateX,
-        TranslateY,
-        // Count of the properties, must be at the end.
-        Count,
-    };
+    GroupProperties mProperties = GroupProperties(this);
+    GroupProperties mStagingProperties = GroupProperties(this);
+    bool mStagingPropertiesDirty = true;
     std::vector< std::unique_ptr<Node> > mChildren;
-    Properties mProperties;
 };
 
 class ANDROID_API Tree : public VirtualLightRefBase {
 public:
-    Tree(Group* rootNode) : mRootNode(rootNode) {}
+    Tree(Group* rootNode) : mRootNode(rootNode) {
+        mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
+    }
     void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
             const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+    void drawStaging(Canvas* canvas);
 
     const SkBitmap& getBitmapUpdateIfDirty();
-    void createCachedBitmapIfNeeded(int width, int height);
-    bool canReuseBitmap(int width, int height);
     void setAllowCaching(bool allowCaching) {
         mAllowCaching = allowCaching;
     }
-    bool setRootAlpha(float rootAlpha) {
-        return VD_SET_PROP(mRootAlpha, rootAlpha);
+    SkPaint* getPaint();
+    void syncProperties() {
+        if (mStagingProperties.mNonAnimatablePropertiesDirty) {
+            mProperties.syncNonAnimatableProperties(mStagingProperties);
+            mStagingProperties.mNonAnimatablePropertiesDirty = false;
+        }
+
+        if (mStagingProperties.mAnimatablePropertiesDirty) {
+            mProperties.syncAnimatableProperties(mStagingProperties);
+        } else {
+            mStagingProperties.syncAnimatableProperties(mProperties);
+        }
+        mStagingProperties.mAnimatablePropertiesDirty = false;
+        mRootNode->syncProperties();
     }
 
-    float getRootAlpha() {
-        return mRootAlpha;
-    }
-    void setViewportSize(float viewportWidth, float viewportHeight) {
-        mViewportWidth = viewportWidth;
-        mViewportHeight = viewportHeight;
-    }
-    SkPaint* getPaint();
-    const SkRect& getBounds() const {
-        return mBounds;
-    }
+    class TreeProperties {
+    public:
+        TreeProperties(Tree* tree) : mTree(tree) {}
+        // Properties that can only be modified by UI thread, therefore sync should
+        // only go from UI to RT
+        struct NonAnimatableProperties {
+            float viewportWidth = 0;
+            float viewportHeight = 0;
+            SkRect bounds;
+            int scaledWidth = 0;
+            int scaledHeight = 0;
+            SkColorFilter* colorFilter = nullptr;
+            ~NonAnimatableProperties() {
+                SkSafeUnref(colorFilter);
+            }
+        } mNonAnimatableProperties;
+        bool mNonAnimatablePropertiesDirty = true;
+
+        float mRootAlpha = 1.0f;
+        bool mAnimatablePropertiesDirty = true;
+
+        void syncNonAnimatableProperties(const TreeProperties& prop) {
+            // Copy over the data that can only be changed in UI thread
+            if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
+                SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
+                        prop.mNonAnimatableProperties.colorFilter);
+            }
+            mNonAnimatableProperties = prop.mNonAnimatableProperties;
+        }
+
+        void setViewportSize(float width, float height) {
+            if (mNonAnimatableProperties.viewportWidth != width
+                    || mNonAnimatableProperties.viewportHeight != height) {
+                mNonAnimatablePropertiesDirty = true;
+                mNonAnimatableProperties.viewportWidth = width;
+                mNonAnimatableProperties.viewportHeight = height;
+                mTree->onPropertyChanged(this);
+            }
+        }
+        void setBounds(const SkRect& bounds) {
+            if (mNonAnimatableProperties.bounds != bounds) {
+                mNonAnimatableProperties.bounds = bounds;
+                mNonAnimatablePropertiesDirty = true;
+                mTree->onPropertyChanged(this);
+            }
+        }
+
+        void setScaledSize(int width, int height) {
+            if (mNonAnimatableProperties.scaledWidth != width
+                    || mNonAnimatableProperties.scaledHeight != height) {
+                mNonAnimatableProperties.scaledWidth = width;
+                mNonAnimatableProperties.scaledHeight = height;
+                mNonAnimatablePropertiesDirty = true;
+                mTree->onPropertyChanged(this);
+            }
+        }
+        void setColorFilter(SkColorFilter* filter) {
+            if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
+                mNonAnimatablePropertiesDirty = true;
+                mTree->onPropertyChanged(this);
+            }
+        }
+        SkColorFilter* getColorFilter() const{
+            return mNonAnimatableProperties.colorFilter;
+        }
+
+        float getViewportWidth() const {
+            return mNonAnimatableProperties.viewportWidth;
+        }
+        float getViewportHeight() const {
+            return mNonAnimatableProperties.viewportHeight;
+        }
+        float getScaledWidth() const {
+            return mNonAnimatableProperties.scaledWidth;
+        }
+        float getScaledHeight() const {
+            return mNonAnimatableProperties.scaledHeight;
+        }
+        void syncAnimatableProperties(const TreeProperties& prop) {
+            mRootAlpha = prop.mRootAlpha;
+        }
+        bool setRootAlpha(float rootAlpha) {
+            if (rootAlpha != mRootAlpha) {
+                mAnimatablePropertiesDirty = true;
+                mRootAlpha = rootAlpha;
+                mTree->onPropertyChanged(this);
+                return true;
+            }
+            return false;
+        }
+        float getRootAlpha() const { return mRootAlpha;}
+        const SkRect& getBounds() const {
+            return mNonAnimatableProperties.bounds;
+        }
+        Tree* mTree;
+    };
+    void onPropertyChanged(TreeProperties* prop);
+    TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
+    const TreeProperties* stagingProperties() { return &mStagingProperties; }
+    PushStagingFunctor* getFunctor() { return &mFunctor;}
+
+    // This should only be called from animations on RT
+    TreeProperties* mutateProperties() { return &mProperties; }
 
 private:
+    class VectorDrawableFunctor : public PushStagingFunctor {
+    public:
+        VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
+        virtual void operator ()() {
+            mTree->syncProperties();
+        }
+    private:
+        Tree* mTree;
+    };
+
+    SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
+    bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
+    bool canReuseBitmap(const SkBitmap&, int width, int height);
+    void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
     // Cap the bitmap size, such that it won't hurt the performance too much
     // and it won't crash due to a very large scale.
     // The drawable will look blurry above this size.
     const static int MAX_CACHED_BITMAP_SIZE;
 
-    bool mCacheDirty = true;
     bool mAllowCaching = true;
-    float mViewportWidth = 0;
-    float mViewportHeight = 0;
-    float mRootAlpha = 1.0f;
-
     std::unique_ptr<Group> mRootNode;
-    SkRect mBounds;
-    SkMatrix mCanvasMatrix;
-    SkPaint mPaint;
-    SkPathMeasure mPathMeasure;
-    SkBitmap mCachedBitmap;
 
+    TreeProperties mProperties = TreeProperties(this);
+    TreeProperties mStagingProperties = TreeProperties(this);
+
+    VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
+
+    SkPaint mPaint;
+    struct Cache {
+        SkBitmap bitmap;
+        bool dirty = true;
+    };
+
+    Cache mStagingCache;
+    Cache mCache;
+
+    PropertyChangedListener mPropertyChangedListener
+            = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
 };
 
 } // namespace VectorDrawable
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6933b2f..63fa788 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -576,7 +576,7 @@
 
 static void destroyPrefetechedNode(RenderNode* node) {
     ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
-    node->destroyHardwareResources();
+    node->destroyHardwareResources(nullptr);
     node->decStrong(nullptr);
 }
 
@@ -641,7 +641,7 @@
     if (mEglManager.hasEglContext()) {
         freePrefetechedLayers();
         for (const sp<RenderNode>& node : mRenderNodes) {
-            node->destroyHardwareResources();
+            node->destroyHardwareResources(nullptr);
         }
         Caches& caches = Caches::getInstance();
         // Make sure to release all the textures we were owning as there won't
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 04223a7..16dd108 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -56,6 +56,7 @@
     enum {
         FrameStats = 1 << 0,
         Reset      = 1 << 1,
+        JankStats  = 1 << 2,
     };
 };
 
@@ -415,7 +416,6 @@
 CREATE_BRIDGE4(dumpProfileInfo, CanvasContext* context, RenderThread* thread,
         int fd, int dumpFlags) {
     args->context->profiler().dumpData(args->fd);
-    args->thread->jankTracker().dump(args->fd);
     if (args->dumpFlags & DumpFlags::FrameStats) {
         args->context->dumpFrames(args->fd);
     }
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 2d1e2e9..5492035 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -218,7 +218,7 @@
 private:
     static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
         node->syncProperties();
-        node->syncDisplayList();
+        node->syncDisplayList(nullptr);
         auto displayList = node->getDisplayList();
         if (displayList) {
             for (auto&& childOp : displayList->getChildren()) {
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index 654ddc6..5471486 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -85,7 +85,9 @@
                 << "Should see conservative offset from PathCache::computeBounds";
         Rect expectedBounds(10, 15, 20, 25);
         expectedBounds.outset(expectedOffset);
+#if !HWUI_NEW_OPS
         EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
+#endif
         Matrix4 expectedModelView;
         expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
         expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index 454011f..95543d3 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -85,7 +85,9 @@
 }
 
 static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) {
+#if !HWUI_NEW_OPS
     EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds);
+#endif
     expectBlendEq(expectedGlop.blend, builtGlop.blend);
     expectFillEq(expectedGlop.fill, builtGlop.fill);
     expectMeshEq(expectedGlop.mesh, builtGlop.mesh);
@@ -136,7 +138,9 @@
     // unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels.
     goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0);
     goldenGlop->transform.modelView.scale(99, 99, 1);
+#if !HWUI_NEW_OPS
     goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70);
+#endif
     goldenGlop->transform.canvas = simpleTranslate;
     goldenGlop->fill.texture.filter = GL_NEAREST;
     expectGlopEq(*goldenGlop, glop);
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
new file mode 100644
index 0000000..7c57a50
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "RenderNode.h"
+#include "TreeInfo.h"
+#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderNode, hasParents) {
+    auto child = TestUtils::createNode(0, 0, 200, 400,
+            [](RenderProperties& props, TestCanvas& canvas) {
+        canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+    });
+    auto parent = TestUtils::createNode(0, 0, 200, 400,
+            [&child](RenderProperties& props, TestCanvas& canvas) {
+        canvas.drawRenderNode(child.get());
+    });
+
+    TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+    EXPECT_TRUE(child->hasParents()) << "Child node has no parent";
+    EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+    TestUtils::recordNode(*parent, [](TestCanvas& canvas) {
+        canvas.drawColor(Color::Amber_500, SkXfermode::kSrcOver_Mode);
+    });
+
+    EXPECT_TRUE(child->hasParents()) << "Child should still have a parent";
+    EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+
+    TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+    EXPECT_FALSE(child->hasParents()) << "Child should be removed";
+    EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
+}
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 9c509d6..d76feec 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -121,7 +121,7 @@
      * @param satIndex the index of the satellite in the list.
      */
     public float getElevationDegrees(int satIndex) {
-        return 0f;
+        return mElevations[satIndex];
     }
 
     /**
diff --git a/location/java/android/location/INetInitiatedListener.aidl b/location/java/android/location/INetInitiatedListener.aidl
index f2f5a32..fc64dd6 100644
--- a/location/java/android/location/INetInitiatedListener.aidl
+++ b/location/java/android/location/INetInitiatedListener.aidl
@@ -1,26 +1,26 @@
-/*

-**

-** Copyright 2008, The Android Open Source Project

-**

-** Licensed under the Apache License, Version 2.0 (the "License");

-** you may not use this file except in compliance with the License.

-** You may obtain a copy of the License at

-**

-**     http://www.apache.org/licenses/LICENSE-2.0

-**

-** Unless required by applicable law or agreed to in writing, software

-** distributed under the License is distributed on an "AS IS" BASIS,

-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-** See the License for the specific language governing permissions and

-** limitations under the License.

-*/

-

-package android.location;

-

-/**

- * {@hide}

- */

-interface INetInitiatedListener

-{

-    boolean sendNiResponse(int notifId, int userResponse);

-}

+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.location;
+
+/**
+ * {@hide}
+ */
+interface INetInitiatedListener
+{
+    boolean sendNiResponse(int notifId, int userResponse);
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3c42161..00eff91 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2149,7 +2149,7 @@
                                 }
                                 if (listener != null) {
                                     Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
-                                            + msg.what + ") for " + msg.obj);
+                                            + msg.arg1 + ") for " + msg.obj);
                                     listener.onAudioFocusChange(msg.arg1);
                                 }
                                 break;
@@ -2157,7 +2157,7 @@
                                 final RecordConfigChangeCallbackData cbData =
                                         (RecordConfigChangeCallbackData) msg.obj;
                                 if (cbData.mCb != null) {
-                                    cbData.mCb.onRecordConfigChanged(cbData.mConfigs);
+                                    cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
                                 }
                                 break;
                             default:
@@ -2746,7 +2746,7 @@
          * @param configs array containing the results of
          *      {@link AudioManager#getActiveRecordingConfigurations()}.
          */
-        public void onRecordConfigChanged(AudioRecordingConfiguration[] configs) {}
+        public void onRecordingConfigChanged(AudioRecordingConfiguration[] configs) {}
     }
 
     private static class AudioRecordingCallbackInfo {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b6ff41e..621129d 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -596,14 +596,14 @@
      * AudioTrack player = new AudioTrack.Builder()
      *         .setAudioAttributes(new AudioAttributes.Builder()
      *                  .setUsage(AudioAttributes.USAGE_ALARM)
-     *                  .setContentType(CONTENT_TYPE_MUSIC)
+     *                  .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
      *                  .build())
      *         .setAudioFormat(new AudioFormat.Builder()
      *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
-     *                 .setSampleRate(441000)
+     *                 .setSampleRate(44100)
      *                 .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
      *                 .build())
-     *         .setBufferSize(minBuffSize)
+     *         .setBufferSizeInBytes(minBuffSize)
      *         .build();
      * </pre>
      * <p>
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index cd2d51d..3d7e744 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -161,9 +161,14 @@
     public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
     /** Type is double. */
     public static final String TAG_EXPOSURE_TIME = "ExposureTime";
-    /** Type is String. */
+    /** Type is double. */
     public static final String TAG_F_NUMBER = "FNumber";
-    /** Type is String. */
+    /**
+     * Type is double.
+     *
+     * @deprecated use {@link #TAG_F_NUMBER} instead
+     */
+    @Deprecated
     public static final String TAG_APERTURE = "FNumber";
     /** Type is String. */
     public static final String TAG_FILE_SOURCE = "FileSource";
@@ -185,9 +190,14 @@
     public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
     /** Type is rational. */
     public static final String TAG_GAIN_CONTROL = "GainControl";
-    /** Type is String. */
+    /** Type is int. */
     public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
-    /** Type is String. */
+    /**
+     * Type is int.
+     *
+     * @deprecated use {@link #TAG_ISO_SPEED_RATINGS} instead
+     */
+    @Deprecated
     public static final String TAG_ISO = "ISOSpeedRatings";
     /** Type is String. */
     public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
@@ -225,8 +235,6 @@
     public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
     /** Type is int. */
     public static final String TAG_SUBSEC_TIME = "SubSecTime";
-    /** Type is int. @hide */
-    public static final String TAG_SUBSECTIME = "SubSecTime";
     /** Type is int. */
     public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
     /** Type is int. */
@@ -437,7 +445,7 @@
             new ExifTag(TAG_F_NUMBER, 33437),
             new ExifTag(TAG_EXPOSURE_PROGRAM, 34850),
             new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852),
-            new ExifTag(TAG_ISO, 34855),
+            new ExifTag(TAG_ISO_SPEED_RATINGS, 34855),
             new ExifTag(TAG_OECF, 34856),
             new ExifTag(TAG_EXIF_VERSION, 36864),
             new ExifTag(TAG_DATETIME_ORIGINAL, 36867),
@@ -1079,12 +1087,16 @@
      *
      * @return two-element array, the offset in the first value, and length in
      *         the second, or {@code null} if no thumbnail was found.
-     * @hide
      */
     public long[] getThumbnailRange() {
+        if (!mHasThumbnail) {
+            return null;
+        }
+
         long[] range = new long[2];
         range[0] = mThumbnailOffset;
         range[1] = mThumbnailLength;
+
         return range;
     }
 
@@ -1147,7 +1159,7 @@
             if (datetime == null) return -1;
             long msecs = datetime.getTime();
 
-            String subSecs = getAttribute(TAG_SUBSECTIME);
+            String subSecs = getAttribute(TAG_SUBSEC_TIME);
             if (subSecs != null) {
                 try {
                     long sub = Long.valueOf(subSecs);
@@ -1539,7 +1551,7 @@
         convertToDouble(TAG_EXPOSURE_TIME);
         convertToDouble(TAG_F_NUMBER);
         convertToDouble(TAG_SUBJECT_DISTANCE);
-        convertToInt(TAG_ISO);
+        convertToInt(TAG_ISO_SPEED_RATINGS);
         convertToDouble(TAG_EXPOSURE_BIAS_VALUE);
         convertToInt(TAG_WHITE_BALANCE);
         convertToInt(TAG_LIGHT_SOURCE);
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 1fee587..983ca75 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -45,8 +45,7 @@
     private static final int NUM_MEDIA_SOUND_STREAMS = 1;
 
     private SoundPool mSoundPool;
-    private int[]     mSoundIds;
-    private int       mSoundIdToPlay;
+    private SoundState[] mSounds;
 
     private static final String[] SOUND_FILES = {
         "/system/media/audio/ui/camera_click.ogg",
@@ -88,22 +87,57 @@
      */
     public static final int STOP_VIDEO_RECORDING  = 3;
 
-    private static final int SOUND_NOT_LOADED = -1;
+    /**
+     * States for SoundState.
+     * STATE_NOT_LOADED             : sample not loaded
+     * STATE_LOADING                : sample being loaded: waiting for load completion callback
+     * STATE_LOADING_PLAY_REQUESTED : sample being loaded and playback request received
+     * STATE_LOADED                 : sample loaded, ready for playback
+     */
+    private static final int STATE_NOT_LOADED             = 0;
+    private static final int STATE_LOADING                = 1;
+    private static final int STATE_LOADING_PLAY_REQUESTED = 2;
+    private static final int STATE_LOADED                 = 3;
 
+    private class SoundState {
+        public final int name;
+        public int id;
+        public int state;
+
+        public SoundState(int name) {
+            this.name = name;
+            id = 0; // 0 is an invalid sample ID.
+            state = STATE_NOT_LOADED;
+        }
+    }
     /**
      * Construct a new MediaActionSound instance. Only a single instance is
      * needed for playing any platform media action sound; you do not need a
      * separate instance for each sound type.
      */
     public MediaActionSound() {
-        mSoundPool = new SoundPool(NUM_MEDIA_SOUND_STREAMS,
-                AudioManager.STREAM_SYSTEM_ENFORCED, 0);
+        mSoundPool = new SoundPool.Builder()
+                .setMaxStreams(NUM_MEDIA_SOUND_STREAMS)
+                .setAudioAttributes(new AudioAttributes.Builder()
+                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                    .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                    .build())
+                .build();
         mSoundPool.setOnLoadCompleteListener(mLoadCompleteListener);
-        mSoundIds = new int[SOUND_FILES.length];
-        for (int i = 0; i < mSoundIds.length; i++) {
-            mSoundIds[i] = SOUND_NOT_LOADED;
+        mSounds = new SoundState[SOUND_FILES.length];
+        for (int i = 0; i < mSounds.length; i++) {
+            mSounds[i] = new SoundState(i);
         }
-        mSoundIdToPlay = SOUND_NOT_LOADED;
+    }
+
+    private int loadSound(SoundState sound) {
+        int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
+        if (id > 0) {
+            sound.state = STATE_LOADING;
+            sound.id = id;
+        }
+        return id;
     }
 
     /**
@@ -118,13 +152,22 @@
      * @see #START_VIDEO_RECORDING
      * @see #STOP_VIDEO_RECORDING
      */
-    public synchronized void load(int soundName) {
+    public void load(int soundName) {
         if (soundName < 0 || soundName >= SOUND_FILES.length) {
             throw new RuntimeException("Unknown sound requested: " + soundName);
         }
-        if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
-            mSoundIds[soundName] =
-                    mSoundPool.load(SOUND_FILES[soundName], 1);
+        SoundState sound = mSounds[soundName];
+        synchronized (sound) {
+            switch (sound.state) {
+            case STATE_NOT_LOADED:
+                if (loadSound(sound) <= 0) {
+                    Log.e(TAG, "load() error loading sound: " + soundName);
+                }
+                break;
+            default:
+                Log.e(TAG, "load() called in wrong state: " + sound + " for sound: "+ soundName);
+                break;
+            }
         }
     }
 
@@ -159,16 +202,31 @@
      * @see #START_VIDEO_RECORDING
      * @see #STOP_VIDEO_RECORDING
      */
-    public synchronized void play(int soundName) {
+    public void play(int soundName) {
         if (soundName < 0 || soundName >= SOUND_FILES.length) {
             throw new RuntimeException("Unknown sound requested: " + soundName);
         }
-        if (mSoundIds[soundName] == SOUND_NOT_LOADED) {
-            mSoundIdToPlay =
-                    mSoundPool.load(SOUND_FILES[soundName], 1);
-            mSoundIds[soundName] = mSoundIdToPlay;
-        } else {
-            mSoundPool.play(mSoundIds[soundName], 1.0f, 1.0f, 0, 0, 1.0f);
+        SoundState sound = mSounds[soundName];
+        synchronized (sound) {
+            switch (sound.state) {
+            case STATE_NOT_LOADED:
+                loadSound(sound);
+                if (loadSound(sound) <= 0) {
+                    Log.e(TAG, "play() error loading sound: " + soundName);
+                    break;
+                }
+                // FALL THROUGH
+
+            case STATE_LOADING:
+                sound.state = STATE_LOADING_PLAY_REQUESTED;
+                break;
+            case STATE_LOADED:
+                mSoundPool.play(sound.id, 1.0f, 1.0f, 0, 0, 1.0f);
+                break;
+            default:
+                Log.e(TAG, "play() called in wrong state: " + sound.state + " for sound: "+ soundName);
+                break;
+            }
         }
     }
 
@@ -176,14 +234,37 @@
             new SoundPool.OnLoadCompleteListener() {
         public void onLoadComplete(SoundPool soundPool,
                 int sampleId, int status) {
-            if (status == 0) {
-                if (mSoundIdToPlay == sampleId) {
-                    soundPool.play(sampleId, 1.0f, 1.0f, 0, 0, 1.0f);
-                    mSoundIdToPlay = SOUND_NOT_LOADED;
+            for (SoundState sound : mSounds) {
+                if (sound.id != sampleId) {
+                    continue;
                 }
-            } else {
-                Log.e(TAG, "Unable to load sound for playback (status: " +
-                        status + ")");
+                int playSoundId = 0;
+                synchronized (sound) {
+                    if (status != 0) {
+                        sound.state = STATE_NOT_LOADED;
+                        sound.id = 0;
+                        Log.e(TAG, "OnLoadCompleteListener() error: " + status +
+                                " loading sound: "+ sound.name);
+                        return;
+                    }
+                    switch (sound.state) {
+                    case STATE_LOADING:
+                        sound.state = STATE_LOADED;
+                        break;
+                    case STATE_LOADING_PLAY_REQUESTED:
+                        playSoundId = sound.id;
+                        sound.state = STATE_LOADED;
+                        break;
+                    default:
+                        Log.e(TAG, "OnLoadCompleteListener() called in wrong state: "
+                                + sound.state + " for sound: "+ sound.name);
+                        break;
+                    }
+                }
+                if (playSoundId != 0) {
+                    soundPool.play(playSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
+                }
+                break;
             }
         }
     };
@@ -195,6 +276,12 @@
      */
     public void release() {
         if (mSoundPool != null) {
+            for (SoundState sound : mSounds) {
+                synchronized (sound) {
+                    sound.state = STATE_NOT_LOADED;
+                    sound.id = 0;
+                }
+            }
             mSoundPool.release();
             mSoundPool = null;
         }
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index b1c1b79..2bd9781 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2666,12 +2666,13 @@
         public static final int HEVCHighTierLevel62 = 0x2000000;
 
         // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
-        public static final int DolbyVisionProfileDvavDer = 0x1;
-        public static final int DolbyVisionProfileDvavDen = 0x2;
-        public static final int DolbyVisionProfileDvheDer = 0x3;
-        public static final int DolbyVisionProfileDvheDen = 0x4;
-        public static final int DolbyVisionProfileDvheDtr = 0x5;
-        public static final int DolbyVisionProfileDvheStn = 0x6;
+        public static final int DolbyVisionProfileDvavPer = 0x1;
+        public static final int DolbyVisionProfileDvavPen = 0x2;
+        public static final int DolbyVisionProfileDvheDer = 0x4;
+        public static final int DolbyVisionProfileDvheDen = 0x8;
+        public static final int DolbyVisionProfileDvheDtr = 0x10;
+        public static final int DolbyVisionProfileDvheStn = 0x20;
+        public static final int DolbyVisionProfileDvheDth = 0x40;
 
         // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
         public static final int DolbyVisionLevelHd24    = 0x1;
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 177344a..24a400e4 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -275,16 +275,23 @@
                     return initDataMap.get(schemeUuid);
                 }
             };
-        } else if (formatMap.containsKey("crypto-key")) {
-            ByteBuffer buf = (ByteBuffer) formatMap.get("crypto-key");
-            buf.rewind();
-            final byte[] data = new byte[buf.remaining()];
-            buf.get(data);
-            return new DrmInitData() {
-                public SchemeInitData get(UUID schemeUuid) {
-                    return new DrmInitData.SchemeInitData("webm", data);
+        } else {
+            int numTracks = getTrackCount();
+            for (int i = 0; i < numTracks; ++i) {
+                Map<String, Object> trackFormatMap = getTrackFormatNative(i);
+                if (!trackFormatMap.containsKey("crypto-key")) {
+                    continue;
                 }
-            };
+                ByteBuffer buf = (ByteBuffer) trackFormatMap.get("crypto-key");
+                buf.rewind();
+                final byte[] data = new byte[buf.remaining()];
+                buf.get(data);
+                return new DrmInitData() {
+                    public SchemeInitData get(UUID schemeUuid) {
+                        return new DrmInitData.SchemeInitData("webm", data);
+                    }
+                };
+            }
         }
         return null;
     }
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index ebe509c..7117fbd 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -34,7 +34,7 @@
 /**
  * MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or
  * webm file as the output and at most one audio and/or one video elementary
- * stream.
+ * stream. MediaMuxer does not support muxing B-frames.
  * <p>
  * It is generally used like this:
  *
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index c1805cb..7c6adad 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -72,7 +72,7 @@
 
     /**
      * Used as an int extra field to denote the page number to subscribe.
-     * The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
+     * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
      *
      * @see #EXTRA_PAGE_SIZE
      */
diff --git a/media/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
index b06e598..2943e60 100644
--- a/media/java/android/media/browse/MediaBrowserUtils.java
+++ b/media/java/android/media/browse/MediaBrowserUtils.java
@@ -50,7 +50,7 @@
             startIndex1 = 0;
             endIndex1 = Integer.MAX_VALUE;
         } else {
-            startIndex1 = pageSize1 * (page1 - 1);
+            startIndex1 = pageSize1 * page1;
             endIndex1 = startIndex1 + pageSize1 - 1;
         }
 
@@ -58,7 +58,7 @@
             startIndex2 = 0;
             endIndex2 = Integer.MAX_VALUE;
         } else {
-            startIndex2 = pageSize2 * (page2 - 1);
+            startIndex2 = pageSize2 * page2;
             endIndex2 = startIndex2 + pageSize2 - 1;
         }
 
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index acf94f4c..03dc699 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -116,10 +116,10 @@
     private final int mType;
     private final boolean mIsHardwareInput;
 
-    // TODO: Remove mLabel and mIconUri when createTvInputInfo() is removed.
-    private String mLabel;
+    // TODO: Remove mIconUri when createTvInputInfo() is removed.
     private Uri mIconUri;
 
+    private final CharSequence mLabel;
     private final int mLabelResId;
     private final Icon mIcon;
     private final Icon mIconStandby;
@@ -161,8 +161,8 @@
         TvInputInfo info = new TvInputInfo.Builder(context, service)
                 .setHdmiDeviceInfo(hdmiDeviceInfo)
                 .setParentId(parentId)
+                .setLabel(label)
                 .build();
-        info.mLabel = label;
         info.mIconUri = iconUri;
         return info;
     }
@@ -215,8 +215,8 @@
                     throws XmlPullParserException, IOException {
         TvInputInfo info = new TvInputInfo.Builder(context, service)
                 .setTvInputHardwareInfo(hardwareInfo)
+                .setLabel(label)
                 .build();
-        info.mLabel = label;
         info.mIconUri = iconUri;
         return info;
     }
@@ -247,7 +247,7 @@
     }
 
     private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
-            int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
+            CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
             String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
             HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
             Bundle extras) {
@@ -255,6 +255,7 @@
         mId = id;
         mType = type;
         mIsHardwareInput = isHardwareInput;
+        mLabel = label;
         mLabelResId = labelResId;
         mIcon = icon;
         mIconStandby = iconStandby;
@@ -570,7 +571,7 @@
         dest.writeString(mId);
         dest.writeInt(mType);
         dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
-        dest.writeString(mLabel);
+        TextUtils.writeToParcel(mLabel, dest, flags);
         dest.writeParcelable(mIconUri, flags);
         dest.writeInt(mLabelResId);
         dest.writeParcelable(mIcon, flags);
@@ -612,7 +613,7 @@
         mId = in.readString();
         mType = in.readInt();
         mIsHardwareInput = in.readByte() == 1;
-        mLabel = in.readString();
+        mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mIconUri = in.readParcelable(null);
         mLabelResId = in.readInt();
         mIcon = in.readParcelable(null);
@@ -660,6 +661,7 @@
 
         private final Context mContext;
         private final ResolveInfo mResolveInfo;
+        private CharSequence mLabel;
         private int mLabelResId;
         private Icon mIcon;
         private Icon mIconStandby;
@@ -746,12 +748,31 @@
         /**
          * Sets the label.
          *
+         * @param label The text to be used as label.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setLabel(CharSequence label) {
+            if (mLabelResId != 0) {
+                throw new IllegalStateException("Resource ID for label is already set.");
+            }
+            this.mLabel = label;
+            return this;
+        }
+
+        /**
+         * Sets the label.
+         *
          * @param resId The resource ID of the text to use.
          * @return This Builder object to allow for chaining of calls to builder methods.
          * @hide
          */
         @SystemApi
         public Builder setLabel(int resId) {
+            if (mLabel != null) {
+                throw new IllegalStateException("Label text is already set.");
+            }
             this.mLabelResId = resId;
             return this;
         }
@@ -868,8 +889,8 @@
                 type = TYPE_TUNER;
             }
             parseServiceMetadata(type);
-            return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabelResId, mIcon,
-                    mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
+            return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
+                    mIcon, mIconStandby, mIconDisconnected, mSetupActivity, mSettingsActivity,
                     mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
                     mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
         }
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index c72a7a0..b4536b1 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -56,7 +56,26 @@
 
 /**
  * Central system API to the overall TV input framework (TIF) architecture, which arbitrates
- * interaction between applications and the selected TV inputs.
+ * interaction between applications and the selected TV inputs. You can retrieve an instance of
+ * this interface with {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.TV_INPUT_SERVICE)}.
+ *
+ * <p>There are three primary parties involved in the TV input framework (TIF) architecture:
+ *
+ * <ul>
+ * <li>The <strong>TV input manager</strong> as expressed by this class is the central point of the
+ * system that manages interaction between all other parts. It is expressed as the client-side API
+ * here which exists in each application context and communicates with a global system service that
+ * manages the interaction across all processes.
+ * <li>A <strong>TV input</strong> implemented by {@link TvInputService} represents an input source
+ * of TV, which can be a pass-through input such as HDMI, or a tuner input which provides broadcast
+ * TV programs. The system binds to the TV input per application’s request.
+ * on implementing TV inputs.
+ * <li><strong>Applications</strong> talk to the TV input manager to list TV inputs and check their
+ * status. Once an application find the input to use, it uses {@link TvView} or
+ * {@link TvRecordingClient} for further interaction such as watching and recording broadcast TV
+ * programs.
+ * </ul>
  */
 public final class TvInputManager {
     private static final String TAG = "TvInputManager";
@@ -824,11 +843,21 @@
 
     /**
      * Interface used to receive events from Hardware objects.
+     *
      * @hide
      */
     @SystemApi
     public abstract static class HardwareCallback {
+        /**
+         * This is called when {@link Hardware} is no longer available for the client.
+         */
         public abstract void onReleased();
+
+        /**
+         * This is called when the underlying {@link TvStreamConfig} has been changed.
+         *
+         * @param configs The new {@link TvStreamConfig}s.
+         */
         public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
     }
 
@@ -1470,18 +1499,41 @@
     }
 
     /**
-     * Returns acquired TvInputManager.Hardware object for given deviceId.
+     * Acquires {@link Hardware} object for the given device ID.
      *
-     * If there are other Hardware object acquired for the same deviceId, calling this method will
-     * preempt the previously acquired object and report {@link HardwareCallback#onReleased} to the
-     * old object.
+     * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+     * acquired Hardware.
+     *
+     * @param deviceId The device ID to acquire Hardware for.
+     * @param callback A callback to receive updates on Hardware.
+     * @param info The TV input which will use the acquired Hardware.
+     * @return Hardware on success, {@code null} otherwise.
+     *
+     * @removed
+     */
+    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
+    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
+            TvInputInfo info) {
+        return acquireTvInputHardware(deviceId, info, callback);
+    }
+
+    /**
+     * Acquires {@link Hardware} object for the given device ID.
+     *
+     * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
+     * acquired Hardware.
+     *
+     * @param deviceId The device ID to acquire Hardware for.
+     * @param callback A callback to receive updates on Hardware.
+     * @param info The TV input which will use the acquired Hardware.
+     * @return Hardware on success, {@code null} otherwise.
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
-    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
-            TvInputInfo info) {
+    public Hardware acquireTvInputHardware(int deviceId, TvInputInfo info,
+            final HardwareCallback callback) {
         try {
             return new Hardware(
                     mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@@ -1503,6 +1555,9 @@
     /**
      * Releases previously acquired hardware object.
      *
+     * @param deviceId The device ID this Hardware was acquired for
+     * @param hardware Hardware to release.
+     *
      * @hide
      */
     @SystemApi
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index ae86632..6954045 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -657,9 +657,9 @@
         if (page == -1 && pageSize == -1) {
             return list;
         }
-        int fromIndex = pageSize * (page - 1);
+        int fromIndex = pageSize * page;
         int toIndex = fromIndex + pageSize;
-        if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
+        if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
             return Collections.EMPTY_LIST;
         }
         if (toIndex > list.size()) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index dde9bda..312d9aa 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -61,7 +61,7 @@
     private static final String[] EXIF_TAGS = {
             ExifInterface.TAG_MAKE,
             ExifInterface.TAG_MODEL,
-            ExifInterface.TAG_APERTURE,
+            ExifInterface.TAG_F_NUMBER,
             ExifInterface.TAG_DATETIME,
             ExifInterface.TAG_EXPOSURE_TIME,
             ExifInterface.TAG_FLASH,
@@ -77,7 +77,7 @@
             ExifInterface.TAG_GPS_TIMESTAMP,
             ExifInterface.TAG_IMAGE_LENGTH,
             ExifInterface.TAG_IMAGE_WIDTH,
-            ExifInterface.TAG_ISO,
+            ExifInterface.TAG_ISO_SPEED_RATINGS,
             ExifInterface.TAG_ORIENTATION,
             ExifInterface.TAG_WHITE_BALANCE
     };
@@ -288,7 +288,7 @@
         // Checks values.
         assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
         assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
-        assertFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
+        assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
         assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
         assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
         assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
@@ -308,7 +308,7 @@
         assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
         assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
         assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
-        assertStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
+        assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
         assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
         assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
     }
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
new file mode 100644
index 0000000..537b171
--- /dev/null
+++ b/packages/CtsShim/Android.mk
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+###########################################################
+# Variant: Privileged app
+
+include $(CLEAR_VARS)
+# this needs to be a privileged application
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShimPriv
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := priv_shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
+
+###########################################################
+# Variant: System app
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShim
+
+#TODO need to find the correct certificate
+#Change in conjunction with cts/hostsidetests/appsecurity/test-apps/IntentFilterApp
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+
diff --git a/packages/CtsShim/priv_shim/AndroidManifest.xml b/packages/CtsShim/priv_shim/AndroidManifest.xml
new file mode 100644
index 0000000..0a3f823
--- /dev/null
+++ b/packages/CtsShim/priv_shim/AndroidManifest.xml
@@ -0,0 +1,157 @@
+<?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.
+-->
+
+<!-- Manifest for the privileged CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.priv.ctsshim">
+    <application android:label="CtsShim">
+
+        <!-- These activities don't actually exist; define them just to test the filters !-->
+
+        <!-- install test; [some] high priority filters granted -->
+        <activity android:name=".InstallPriority">
+            <!-- normal actions; priority will be granted -->
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEARCH" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+
+            <!-- protected actions; priority will be denied -->
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SENDTO" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; single, equivalent filter -->
+        <activity android:name=".UpgradeMatch">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.MATCH" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; multiple, equivalent filters -->
+        <activity android:name=".UpgradeMatchMultiple">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+
+            <intent-filter android:priority="150">
+                <action android:name="com.android.cts.action.MATCH_MULTIPLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="http" />
+                <data android:scheme="https" />
+                <data android:host="www.google.com" android:port="80" />
+                <data android:host="www.google.com" android:port="8080" />
+                <data android:host="goo.gl" android:port="443" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; lower priority -->
+        <activity android:name=".UpgradeLowerPriority">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.LOWER_PRIORITY" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; action subset -->
+        <activity android:name=".UpgradeActionSubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.ACTION_SUB" />
+                <action android:name="com.android.cts.action.ACTION_SUB_2" />
+                <action android:name="com.android.cts.action.ACTION_SUB_3" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; category subset -->
+        <activity android:name=".UpgradeCategorySubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.CATEGORY_SUB" />
+                <category android:name="android.intent.category.INFO" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; scheme subset -->
+        <activity android:name=".UpgradeSchemeSubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.SCHEME_SUB" />
+                <data android:scheme="content" />
+                <data android:scheme="flubber" />
+                <data android:scheme="zoodle" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; authority subset -->
+        <activity android:name=".UpgradeAuthoritySubset">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.AUTHORITY_SUB" />
+                <data android:host="www.google.com" android:port="80" />
+                <data android:host="www.google.com" android:port="8080" />
+                <data android:host="mail.google.com" android:port="80" />
+                <data android:host="goo.gl" android:port="443" />
+            </intent-filter>
+        </activity>
+
+
+        <!-- upgrade test; new action -->
+        <activity android:name=".UpgradeNewAction">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_ACTION" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; new category -->
+        <activity android:name=".UpgradeNewCategory">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_CATEGORY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; new scheme -->
+        <activity android:name=".UpgradeNewScheme">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_SCHEME" />
+                <data android:scheme="content" />
+            </intent-filter>
+        </activity>
+
+        <!-- upgrade test; new authority -->
+        <activity android:name=".UpgradeNewAuthority">
+            <intent-filter android:priority="100">
+                <action android:name="com.android.cts.action.NEW_AUTHORITY" />
+                <data android:host="www.google.com" android:port="80" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
+
diff --git a/packages/CtsShim/shim/AndroidManifest.xml b/packages/CtsShim/shim/AndroidManifest.xml
new file mode 100644
index 0000000..ee4b547
--- /dev/null
+++ b/packages/CtsShim/shim/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+
+<!-- Manifest for the system CTS shim -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.system.ctsshim">
+    <application android:label="CtsShim">
+
+        <!-- These activities don't actually exist; define them just to test the filters !-->
+
+        <!-- install test; high priority filter DENIED -->
+        <activity android:name=".InstallPriority">
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEARCH" />
+                <category android:name="android.intent.category.INFO" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.SENDTO" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
+
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 95c6f1f..85e7a7a 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -86,6 +86,10 @@
             android:showAsAction="never"
             android:visible="false" />
         <item
+            android:id="@+id/menu_advanced"
+            android:showAsAction="never"
+            android:visible="false" />
+        <item
             android:id="@+id/menu_settings"
             android:title="@string/menu_settings"
             android:showAsAction="never"
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index a3fdd78..75d9b4b 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vee \"<xliff:g id="NAME">%1$s</xliff:g>\" uit?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vee vouer \"<xliff:g id="NAME">%1$s</xliff:g>\" en sy inhoud uit?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> lêers uit?</item>
+      <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> lêer uit?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> vouers en hul inhoud uit?</item>
+      <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> vouer en sy inhoud uit?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> items uit?</item>
+      <item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> item uit?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index df73bed..922b9ca 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"«<xliff:g id="NAME">%1$s</xliff:g>» ይሰረዝ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"አቃፊ «<xliff:g id="NAME">%1$s</xliff:g>» እና ይዘቶቹ ይሰረዙ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> አቃፊዎች እና ይዘቶቻቸው ይሰረዙ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> አቃፊዎች እና ይዘቶቻቸው ይሰረዙ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎች ይሰረዙ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ንጥሎች ይሰረዙ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index d92eb5f..f48c542 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -153,7 +153,28 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"هل تريد حذف \"<xliff:g id="NAME">%1$s</xliff:g>\"؟"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"هل تريد حذف المجلد \"<xliff:g id="NAME">%1$s</xliff:g>\" ومحتوياته؟"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+      <item quantity="two">هل تريد حذف ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+      <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات؟</item>
+      <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا؟</item>
+      <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
+      <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلد ومحتوياته؟</item>
+      <item quantity="two">هل تريد حذف مجلدين (<xliff:g id="COUNT_1">%1$d</xliff:g>) ومحتوياتهما؟</item>
+      <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلدات ومحتوياتها؟</item>
+      <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلدًا ومحتويات هذه المجلدات؟</item>
+      <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> مجلد ومحتويات هذه المجلدات؟</item>
+      <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> مجلد ومحتوياته؟</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="zero">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر؟</item>
+      <item quantity="two">هل تريد حذف عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)؟</item>
+      <item quantity="few">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عناصر؟</item>
+      <item quantity="many">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصرًا؟</item>
+      <item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر؟</item>
+      <item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر؟</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 632fa6b..a4d6f51 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" silinsin?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" qovluğu və onun məzmunu silinsin?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> fayl silinsin?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fayl silinsin?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> qovluq və onun məzmunu silinsin?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> qovluq və onun məzmunu silinsin?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> element silinsin?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> element silinsin?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 2d679ea..2c4fe5c 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -129,7 +129,19 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li da izbrišete „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li da izbrišete direktorijum „<xliff:g id="NAME">%1$s</xliff:g>“ i njegov sadržaj?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+      <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijum i njihov sadržaj?</item>
+      <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijuma i njihov sadržaj?</item>
+      <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> direktorijuma i njihov sadržaj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+      <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+      <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-be-rBY/strings.xml b/packages/DocumentsUI/res/values-be-rBY/strings.xml
index abd4679..6e4113e 100644
--- a/packages/DocumentsUI/res/values-be-rBY/strings.xml
+++ b/packages/DocumentsUI/res/values-be-rBY/strings.xml
@@ -135,11 +135,24 @@
       <item quantity="many">Выбрана <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Выбрана <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Выдаліць \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Выдаліць папку \"<xliff:g id="NAME">%1$s</xliff:g>\" і яе змесціва?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлы?</item>
+      <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файлаў?</item>
+      <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папку і іх змесціва?</item>
+      <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папкі і іх змесціва?</item>
+      <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папак і іх змесціва?</item>
+      <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> папкі і іх змесціва?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемент?</item>
+      <item quantity="few">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементы?</item>
+      <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементаў?</item>
+      <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемента?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 4822adb..4b24a0e 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Искате ли да изтриете „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Искате ли да изтриете папката „<xliff:g id="NAME">%1$s</xliff:g>“ и съдържанието в нея?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+      <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> файл?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> папки и съдържанието в тях?</item>
+      <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> папка и съдържанието в нея?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> елемента?</item>
+      <item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> елемент?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 5709692..79cd382 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" মুছবেন?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ফোল্ডার এবং এটির সামগ্রীগুলিকে মুছবেন?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফোল্ডার এবং সেগুলির সামগ্রী মুছবেন?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফোল্ডার এবং সেগুলির সামগ্রী মুছবেন?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছবেন?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি আইটেম মুছবেন?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 9c94a05..14d6716 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -127,11 +127,21 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> stavki je odabrano</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li izbrisati \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li izbrisati folder \"<xliff:g id="NAME">%1$s</xliff:g>\" i njegov sadržaj?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> folder i njihov sadržaj?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> foldera i njihov sadržaj?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> foldera i njihov sadržaj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 4ecec9f..73998b1 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -111,7 +111,7 @@
     <string name="rename_error" msgid="4203041674883412606">"No s\'ha pogut canviar el nom del document"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
     <string name="open_external_dialog_request" msgid="5789329484285817629">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés al directori <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> de l\'emmagatzematge <xliff:g id="STORAGE"><i>^3</i></xliff:g>?"</string>
-    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de l\'emmagatzematge <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Vols que l\'aplicació <xliff:g id="APPNAME"><b>^1</b></xliff:g> tingui accés a les dades de <xliff:g id="STORAGE"><i>^2</i></xliff:g>, incloses les fotos i els vídeos?"</string>
     <string name="never_ask_again" msgid="4295278542972859268">"No m\'ho demanis més"</string>
     <string name="allow" msgid="7225948811296386551">"Permet"</string>
     <string name="deny" msgid="2081879885755434506">"Denega"</string>
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vols suprimir el fitxer <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vols suprimir la carpeta <xliff:g id="NAME">%1$s</xliff:g> i el seu contingut?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers?</item>
+      <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> carpetes i el seu contingut?</item>
+      <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta i el seu contingut?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> elements?</item>
+      <item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 3c6e81d..ffabe77 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Smazat soubor <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Smazat složku <xliff:g id="NAME">%1$s</xliff:g> a její obsah?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> soubory?</item>
+      <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souboru?</item>
+      <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souborů?</item>
+      <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> soubor?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složky a jejich obsah?</item>
+      <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složky a jejich obsah?</item>
+      <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> složek a jejich obsah?</item>
+      <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> složku a její obsah?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="many">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> položek?</item>
+      <item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> položku?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 679506b..bf328ab 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vil du slette \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vil du slette mappen \"<xliff:g id="NAME">%1$s</xliff:g>\" og dens indhold?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> fil?</item>
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mappe og dens indhold?</item>
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mapper og deres indhold?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> element?</item>
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> elementer?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index b48afb0..9ccb564 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" löschen?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ordner \"<xliff:g id="NAME">%1$s</xliff:g>\" und dessen Inhalte löschen?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Dateien löschen?</item>
+      <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Datei löschen?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Ordner und deren Inhalte löschen?</item>
+      <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Ordner und dessen Inhalte löschen?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Elemente löschen?</item>
+      <item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Element löschen?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 3872c40..f23a35d 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Να διαγραφεί το αρχείο \"<xliff:g id="NAME">%1$s</xliff:g>\";"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Να διαγραφεί ο φάκελος \"<xliff:g id="NAME">%1$s</xliff:g>\" και τα περιεχόμενά του;"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία;</item>
+      <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείο;</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> φάκελοι και τα περιεχόμενά τους;</item>
+      <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> φάκελος και τα περιεχόμενά του;</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> στοιχεία;</item>
+      <item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> στοιχείο;</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 8a56f6c..f82f988 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 8a56f6c..f82f988 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 8a56f6c..f82f988 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Delete \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Delete folder \"<xliff:g id="NAME">%1$s</xliff:g>\" and its contents?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> folders and their contents?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> folder and its contents?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> items?</item>
+      <item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 3f36f41..5c823d0 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"¿Deseas borrar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"¿Deseas borrar la carpeta \"<xliff:g id="NAME">%1$s</xliff:g>\" y su contenido?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+      <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item>
+      <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+      <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index a0da06c..60d1d1c 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -111,7 +111,7 @@
     <string name="rename_error" msgid="4203041674883412606">"Error al cambiar el nombre del documento"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
     <string name="open_external_dialog_request" msgid="5789329484285817629">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda al directorio <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> (<xliff:g id="STORAGE"><i>^3</i></xliff:g>)?"</string>
-    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda a tus datos, incluidos los vídeos y las fotos de <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"¿Permitir que <xliff:g id="APPNAME"><b>^1</b></xliff:g> acceda a tus datos, incluidos los vídeos y las fotos, de <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
     <string name="never_ask_again" msgid="4295278542972859268">"No volver a preguntar"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"¿Eliminar <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"¿Eliminar la carpeta <xliff:g id="NAME">%1$s</xliff:g> y su contenido?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+      <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item>
+      <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+      <item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index d49b320..0fdc435 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Kas kustutada fail „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Kas kustutada kaust „<xliff:g id="NAME">%1$s</xliff:g>” ja selle sisu?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> faili?</item>
+      <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> kausta ja nende sisu?</item>
+      <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> kaust ja selle sisu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> üksust?</item>
+      <item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> üksus?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 085f148..b54e542 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ezabatu nahi duzu?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" karpeta eta bertako edukia ezabatu nahi duzu?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi ezabatu nahi dituzu?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi ezabatu nahi duzu?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> karpeta eta beren eduki guztia ezabatu nahi duzu?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> karpeta eta bere eduki guztia ezabatu nahi duzu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementu ezabatu nahi dituzu?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elementu ezabatu nahi duzu?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 114c7d0..cc7eeb5 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one">‏<xliff:g id="COUNT_1">%1$d</xliff:g> مورد انتخاب شد</item>
       <item quantity="other">‏<xliff:g id="COUNT_1">%1$d</xliff:g> مورد انتخاب شد</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"«<xliff:g id="NAME">%1$s</xliff:g>» حذف شود؟"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"پوشه «<xliff:g id="NAME">%1$s</xliff:g>» و محتوای آن حذف شود؟"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> پوشه و محتوای آن‌ها حذف شود؟</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> پوشه و محتوای آن‌ها حذف شود؟</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف شود؟</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف شود؟</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 46f863f..17e4d75 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Poistetaanko <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Poistetaanko kansio <xliff:g id="NAME">%1$s</xliff:g> ja sen sisältö?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa?</item>
+      <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> kansiota ja niiden sisältö?</item>
+      <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> kansio ja sen sisältö?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> kohdetta?</item>
+      <item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> kohde?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index b78b10e..5dbf5ebe 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Supprimer « <xliff:g id="NAME">%1$s</xliff:g> »?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Supprimer le dossier «  <xliff:g id="NAME">%1$s</xliff:g> » et son contenu?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 63e28bf..127d0da 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Supprimer \"<xliff:g id="NAME">%1$s</xliff:g>\" ?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Supprimer le dossier \"<xliff:g id="NAME">%1$s</xliff:g>\" et son contenu ?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier ?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu ?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément ?</item>
+      <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 9ce9ebd..4cce3c9 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Queres eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Queres eliminar o cartafol \"<xliff:g id="NAME">%1$s</xliff:g>\" e o seu contido?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> cartafoles e os seus contidos?</item>
+      <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> cartafol e os seus contidos?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item>
+      <item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 6c2bb3e..1db54f9 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ને કાઢી નાખીએ?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ફોલ્ડર અને તેની સામગ્રીઓને કાઢી નાખીએ?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફોલ્ડર અને તેમની સામગ્રીઓ કાઢી નાખીએ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફોલ્ડર અને તેમની સામગ્રીઓ કાઢી નાખીએ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખીએ?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> આઇટમ કાઢી નાખીએ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 9c27556..de1e25e 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" को हटाएं?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" फ़ोल्डर और उसकी सामग्रियां हटाएं?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ोल्डर और उनकी सामग्री हटाएं?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ोल्डर और उनकी सामग्री हटाएं?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम हटाएं?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आइटम हटाएं?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 58e709b..bf91c6a 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -129,7 +129,19 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Želite li izbrisati datoteku \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Želite li izbrisati mapu \"<xliff:g id="NAME">%1$s</xliff:g>\" i njezin sadržaj?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapu i njihov sadržaj?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mape i njihov sadržaj?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapa i njihov sadržaj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavku?</item>
+      <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
+      <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 1936214..f955318 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Törli a következőt: „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Törli „<xliff:g id="NAME">%1$s</xliff:g>” mappát a tartalmával együtt?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
+      <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> mappát a tartalmukkal együtt?</item>
+      <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> mappát a tartalmával együtt?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> elemet?</item>
+      <item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> elemet?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 57af718..b1af92c 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ջնջե՞լ «<xliff:g id="NAME">%1$s</xliff:g>» ֆայլը:"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ջնջե՞լ «<xliff:g id="NAME">%1$s</xliff:g>» պանակը՝ բովանդակության հետ մեկտեղ:"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> պանակ՝ բովանդակության հետ մեկտեղ:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> պանակ՝ բովանդակության հետ մեկտեղ:</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> տարր:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> տարր:</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 6621c9171..87576fb 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Hapus \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Hapus folder \"<xliff:g id="NAME">%1$s</xliff:g>\" dan kontennya?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> folder dan kontennya?</item>
+      <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> folder dan kontennya?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+      <item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 4265606..d3be73a 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Eyða „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Eyða möppunni „<xliff:g id="NAME">%1$s</xliff:g>“ og öllu innihaldi hennar?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá?</item>
+      <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> möppu og innihaldi þeirra?</item>
+      <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> möppum og innihaldi þeirra?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> atriði?</item>
+      <item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> atriðum?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 7599180..736d31c 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Eliminare \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Eliminare la cartella \"<xliff:g id="NAME">%1$s</xliff:g>\" e i relativi contenuti?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> cartelle e i relativi contenuti?</item>
+      <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> cartella e i relativi contenuti?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi?</item>
+      <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 2e2020c..2446a4b 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -135,11 +135,24 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> נבחר</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"האם למחוק את \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"האם למחוק את התיקייה \"<xliff:g id="NAME">%1$s</xliff:g>\" ואת התוכן שלה?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> קובץ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+      <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+      <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> תיקיות ואת התוכן שלהן?</item>
+      <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> תיקייה ואת התוכן שלה?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="two">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+      <item quantity="many">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+      <item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים?</item>
+      <item quantity="one">האם למחוק <xliff:g id="COUNT_0">%1$d</xliff:g> פריט?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 1ba405f..dc39b99 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"「<xliff:g id="NAME">%1$s</xliff:g>」を削除しますか?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"フォルダ「<xliff:g id="NAME">%1$s</xliff:g>」とそのコンテンツを削除しますか?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除しますか?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のフォルダとそのコンテンツを削除しますか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のフォルダとそのコンテンツを削除しますか?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個の項目を削除しますか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個の項目を削除しますか?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index c1624e3..0af8dd9 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other">არჩეულია <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">არჩეულია <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"გსურთ, წაშალოთ „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"გსურთ, წაშალოთ საქაღალდე „<xliff:g id="NAME">%1$s</xliff:g>“ და მისი შიგთავსი?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის წაშლა?</item>
+      <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის წაშლა?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> საქაღალდისა და მათი შიგთავსის წაშლა?</item>
+      <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> საქაღალდისა და მისი შიგთავსის წაშლა?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ერთეულის წაშლა?</item>
+      <item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ერთეულის წაშლა?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 904ca5d..3d6b758 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -111,7 +111,7 @@
     <string name="rename_error" msgid="4203041674883412606">"Құжат қайта аталмады"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
     <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> қолданбасына <xliff:g id="STORAGE"><i>^3</i></xliff:g> қоймасындағы <xliff:g id="DIRECTORY"><i>^2</i></xliff:g> каталогына өтуге рұқсат беру керек пе?"</string>
-    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> <xliff:g id="STORAGE"><i>^2</i></xliff:g> қоймасындағы деректерге, соның ішінде, фотосуреттерге және бейнелерге қатынас беру керек пе?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> <xliff:g id="STORAGE"><i>^2</i></xliff:g> қоймасындағы деректерге, соның ішінде фотосуреттерге және бейнелерге кіру мүмкіндігін беру керек пе?"</string>
     <string name="never_ask_again" msgid="4295278542972859268">"Қайта сұралмасын"</string>
     <string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
     <string name="deny" msgid="2081879885755434506">"Бас тарту"</string>
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" жою керек пе?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" қалтасын және оның мазмұнын жою керек пе?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды жою керек пе?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> қалтаны ішіндегісімен бірге жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> қалтаны ішіндегісімен бірге жою керек пе?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> элементті жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> элементті жою керек пе?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index ca0fa4c..0eb1396 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"លុប \"<xliff:g id="NAME">%1$s</xliff:g>\" ឬ?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"លុបថតឯកសារ \"<xliff:g id="NAME">%1$s</xliff:g>\" និងមាតិការបស់វាឬ?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">លុបឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> ច្បាប់ឬ?</item>
+      <item quantity="one">លុបឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> ច្បាប់ឬ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">លុបថតឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> និងមាតិការបស់វាឬ?</item>
+      <item quantity="one">លុបថតឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> និងមាតិការបស់វាឬ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">លុបធាតុ <xliff:g id="COUNT_1">%1$d</xliff:g> ឬ?</item>
+      <item quantity="one">លុបធាតុ <xliff:g id="COUNT_0">%1$d</xliff:g> ឬ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 6287274..a5a8ab2 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಅಳಿಸುವುದೇ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಫೋಲ್ಡರ್‌ ಮತ್ತು ಅದರ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್‌ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್‌ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 1b553b5..9975ce0 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"<xliff:g id="NAME">%1$s</xliff:g>을(를) 삭제하시겠습니까?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\'<xliff:g id="NAME">%1$s</xliff:g>\' 폴더와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+      <item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">폴더 <xliff:g id="COUNT_1">%1$d</xliff:g>개와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?</item>
+      <item quantity="one">폴더 <xliff:g id="COUNT_0">%1$d</xliff:g>개와 폴더에 포함된 콘텐츠를 삭제하시겠습니까?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">항목 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+      <item quantity="one">항목 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index f4981b9..be2aca8 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" жок кылынсынбы?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" куржуну мазмуну менен жок кылынсынбы?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынсынбы?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынсынбы?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> куржун мазмуну менен жок кылынсынбы?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> нерсе жок кылынчынбы?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> нерсе жок кылынчынбы?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 4203241..ed96464 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ລຶບ \"<xliff:g id="NAME">%1$s</xliff:g>\" ອອກບໍ?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ລຶບໂຟນເດີ \"<xliff:g id="NAME">%1$s</xliff:g>\" ແລະ ເນື້ອຫາທັງໝົດຂອງມັນອອກບໍ?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+      <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໂຟນເດີ ແລະ ເນື້ອຫາຂອງມັນອອກບໍ?</item>
+      <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໂຟນເດີ ແລະ ເນື້ອຫາຂອງມັນອອກບໍ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ລາຍການອອກບໍ?</item>
+      <item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ລາຍການອອກບໍ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 5114854..0e95ea0 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ištrinti „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ištrinti aplanką „<xliff:g id="NAME">%1$s</xliff:g>“ ir jo turinį?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failą?</item>
+      <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+      <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo?</item>
+      <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplanką ir jų turinį?</item>
+      <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplankus ir jų turinį?</item>
+      <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplanko ir jų turinį?</item>
+      <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> aplankų ir jų turinį?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementą?</item>
+      <item quantity="few">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementus?</item>
+      <item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elemento?</item>
+      <item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> elementų?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 8ee161d..9f39f2e 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -129,7 +129,19 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vai izdzēst failu “<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vai izdzēst mapi “<xliff:g id="NAME">%1$s</xliff:g>” un tās saturu?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+      <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu?</item>
+      <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapes un to saturu?</item>
+      <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapi un to saturu?</item>
+      <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> mapes un to saturu?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="zero">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus?</item>
+      <item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumu?</item>
+      <item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> vienumus?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 5fb64f1..bc3b7fa 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Да се избрише „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Да се избрише папката „<xliff:g id="NAME">%1$s</xliff:g>“ и нејзините содржини?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+      <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> папка и нивните содржини?</item>
+      <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> папки и нивните содржини?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> ставка?</item>
+      <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> ставки?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index afb26a0..9a7509f 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ഇല്ലാതാക്കണോ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" എന്ന ഫോൾഡറും അതിലെ ഉള്ളടങ്ങളും ഇല്ലാതാക്കണോ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണോ?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണോ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫോൾഡറുകളും അവയിലെ ഉള്ളടക്കങ്ങളും ഇല്ലാതാക്കണോ?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫോൾഡറും അതിലെ ഉള്ളടക്കങ്ങളും ഇല്ലാതാക്കണോ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഇനങ്ങൾ ഇല്ലാതാക്കണോ?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഇനം ഇല്ലാതാക്കണോ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 2890908..f424f8e 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"-г устгах уу?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" фолдер болон үүний агуулгыг устгах уу?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлыг устгах уу?</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> файлыг устгах уу?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> фолдер болон агуулгуудыг нь устгах уу?</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> фолдер болон агуулгыг нь устгах уу?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> зүйлийг устгах уу?</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> зүйлийг устгах уу?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index e850b26..556c1e6 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडला</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" हटवायची?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" फोल्डर आणि त्यामधील सामग्री हटवायची?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल हटवायची?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फायली हटवायच्या?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डर आणि त्यामधील सामग्री हटवायची?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डर आणि त्यामधील सामग्री हटवायची?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवायचा?</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> आयटम हटवायचे?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 374cbb0..0f2af2f 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Padamkan \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Padamkan folder \"<xliff:g id="NAME">%1$s</xliff:g>\" dan kandungannya?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail?</item>
+      <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> folder dan kandungannya?</item>
+      <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> folder dan kandungannya?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+      <item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 80afcfb..6acbc80 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ကိုဖျက်မလား။"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ဖိုင်တွဲနှင့် ၎င်းတွင်ပါဝင်သည့် အကြောင်းအရာများကို ဖျက်မလား။"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">ဖိုင် <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+      <item quantity="one">ဖိုင် <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">ဖိုင်တွဲ <xliff:g id="COUNT_1">%1$d</xliff:g> ခုနှင့် ၎င်း၏အကြောင်းအရာများကို ဖျက်မလား။</item>
+      <item quantity="one">ဖိုင်တွဲ <xliff:g id="COUNT_0">%1$d</xliff:g> ခုနှင့် ၎င်း၏အကြောင်းအရာများကို ဖျက်မလား။</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">အကြောင်းအရာ <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+      <item quantity="one">အကြောင်းအရာ <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 8349a13..c2c983e 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vil du slette «<xliff:g id="NAME">%1$s</xliff:g>»?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vil du slette «<xliff:g id="NAME">%1$s</xliff:g>»-mappen og innholdet i den?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> mapper og innholdet i dem?</item>
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> mappe og innholdet i den?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> elementer?</item>
+      <item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index a110742..31c4c2c 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> लाई चयन गरियो</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> लाई चयन गरियो</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" लाई मेट्ने हो?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"फोल्डर \"<xliff:g id="NAME">%1$s</xliff:g>\" र यसका सामग्रीहरूलाई मेट्ने हो?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्ने हो?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्ने हो?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फोल्डरहरू र तिनीहरूका सामग्रीहरूलाई मेट्ने हो?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फोल्डर र यसका सामग्रीहरूलाई मेट्ने हो?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> वस्तुहरूलाई मेट्ने हो?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> वस्तुलाई मेट्ने हो?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 27796cf..385b507 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"<xliff:g id="NAME">%1$s</xliff:g> verwijderen?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Map <xliff:g id="NAME">%1$s</xliff:g> en de bijbehorende inhoud verwijderen?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden verwijderen?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand verwijderen?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> mappen en de bijbehorende inhoud verwijderen?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> map en de bijbehorende inhoud verwijderen?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> items verwijderen?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> item verwijderen?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 503bc0d..7603f58 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀ ਗਈ</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀਆਂ ਗਈਆਂ</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ਕੀ \"<xliff:g id="NAME">%1$s</xliff:g>\" ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ਫੋਲਡਰ \"<xliff:g id="NAME">%1$s</xliff:g>\" ਅਤੇ ਉਸ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+      <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫੋਲਡਰਾਂ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+      <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫੋਲਡਰਾਂ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+      <item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਆਈਟਮਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 7f0b274..b234a9e 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Usunąć „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Usunąć folder „<xliff:g id="NAME">%1$s</xliff:g>” i jego zawartość?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliki?</item>
+      <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików?</item>
+      <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku?</item>
+      <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> plik?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> foldery wraz z zawartością?</item>
+      <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> folderów wraz z zawartością?</item>
+      <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> folderu wraz z zawartością?</item>
+      <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> folder wraz z zawartością?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementy?</item>
+      <item quantity="many">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementów?</item>
+      <item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> elementu?</item>
+      <item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index d34b7b6..634ac96 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Excluir \" <xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Excluir pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e o respectivo conteúdo?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 7c82410..5440801 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Pretende eliminar \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Pretende eliminar a pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e os respetivos conteúdos?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e os respetivos conteúdos?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> pasta e os respetivos conteúdos?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index d34b7b6..634ac96 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Excluir \" <xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Excluir pasta \"<xliff:g id="NAME">%1$s</xliff:g>\" e o respectivo conteúdo?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> pastas e o respectivo conteúdo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+      <item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> itens?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 54458f1..3dc93ef 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -129,7 +129,19 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ștergeți „<xliff:g id="NAME">%1$s</xliff:g>”?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ștergeți dosarul „<xliff:g id="NAME">%1$s</xliff:g>” și conținutul acestuia?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere?</item>
+      <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere?</item>
+      <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> fișier?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> dosare și conținutul acestora?</item>
+      <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de dosare și conținutul acestora?</item>
+      <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> dosar și conținutul acestuia?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> elemente?</item>
+      <item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de elemente?</item>
+      <item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> element?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 2eda9ec..fef3015 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Удалить файл \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Удалить папку \"<xliff:g id="NAME">%1$s</xliff:g>\" со всем содержимым?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папку со всем содержимым?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папки со всем содержимым?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папок со всем содержимым?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> папки со всем содержимым?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объект?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объекта?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объектов?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> объекта?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 1dc9a2b..d49c2f3 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>ක් තෝරන ලදී</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ක් තෝරන ලදී</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" මකන්නද?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ෆෝල්ඩරය හා එහි අන්තර්ගත මකන්නද?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+      <item quantity="other">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">ෆෝල්ඩර <xliff:g id="COUNT_1">%1$d</xliff:g> ක් හා එහි අන්තර්ගත මකන්නද?</item>
+      <item quantity="other">ෆෝල්ඩර <xliff:g id="COUNT_1">%1$d</xliff:g> ක් හා එහි අන්තර්ගත මකන්නද?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+      <item quantity="other">අයිතම <xliff:g id="COUNT_1">%1$d</xliff:g> ක් මකන්නද?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index da91574..bd75175 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Odstrániť <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Odstrániť priečinok <xliff:g id="NAME">%1$s</xliff:g> a jeho obsah?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory?</item>
+      <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru?</item>
+      <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov?</item>
+      <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinky a ich obsah?</item>
+      <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinka a jeho obsah?</item>
+      <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> priečinkov a ich obsah?</item>
+      <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> priečinok a jeho obsah?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="few">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="many">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položky?</item>
+      <item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> položiek?</item>
+      <item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> položku?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 9a7b477..78ec8fe 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ali želite izbrisati »<xliff:g id="NAME">%1$s</xliff:g>«?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ali želite izbrisati mapo »<xliff:g id="NAME">%1$s</xliff:g>« in njeno vsebino?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteko?</item>
+      <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteki?</item>
+      <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapo in njihovo vsebino?</item>
+      <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mapi in njihovo vsebino?</item>
+      <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> mape in njihovo vsebino?</item>
+      <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> map in njihovo vsebino?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> element?</item>
+      <item quantity="two">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elementa?</item>
+      <item quantity="few">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elemente?</item>
+      <item quantity="other">Ali želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> elementov?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 6b41c60..662e7f0 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Të fshihet \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Të fshihet dosja \"<xliff:g id="NAME">%1$s</xliff:g>\" dhe përmbajtja e saj?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
+      <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> dosje dhe përmbajtjet e saj?</item>
+      <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> dosje dhe përmbajtjet e saj?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> artikuj?</item>
+      <item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> artikull?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index b6ccf45..690f81c 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -129,7 +129,19 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Желите ли да избришете „<xliff:g id="NAME">%1$s</xliff:g>“?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Желите ли да избришете директоријум „<xliff:g id="NAME">%1$s</xliff:g>“ и његов садржај?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку?</item>
+      <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке?</item>
+      <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријум и њихов садржај?</item>
+      <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријума и њихов садржај?</item>
+      <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> директоријума и њихов садржај?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставку?</item>
+      <item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставке?</item>
+      <item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> ставки?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 67bbfdf..1849782 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Vill du radera <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Vill du radera mappen <xliff:g id="NAME">%1$s</xliff:g> och dess innehåll?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+      <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g>  mappar och deras innehåll?</item>
+      <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> mapp och dess innehåll?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Vill du radera <xliff:g id="COUNT_1">%1$d</xliff:g> objekt?</item>
+      <item quantity="one">Vill du radera <xliff:g id="COUNT_0">%1$d</xliff:g> objekt?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 168b63a..bf4b744 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Ungependa kufuta \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Ungependa kufuta folda ya \"<xliff:g id="NAME">%1$s</xliff:g>\" na maudhui yake?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="one">Ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Ungependa kufuta folda <xliff:g id="COUNT_1">%1$d</xliff:g> na maudhui yaliyomo?</item>
+      <item quantity="one">Ungependa kufuta folda <xliff:g id="COUNT_0">%1$d</xliff:g> na maudhui yaliyomo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Ungependa kufuta vipengee <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="one">Ungependa kufuta kipengee <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 43543c6..43d29e2 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"ஐ நீக்கவா?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" கோப்புறையையும் அதன் உள்ளடக்கத்தையும் நீக்கவா?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்கவா?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்கவா?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புறைகளையும் அவற்றின் உள்ளடக்கத்தையும் நீக்கவா?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்புறையையும் அதன் உள்ளடக்கத்தையும் நீக்கவா?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> உருப்படிகளை நீக்கவா?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> உருப்படியை நீக்கவா?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 47d2c48..c9233ec 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\"ని తొలగించాలా?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ఫోల్డర్‌ని మరియు అందులోని కంటెంట్‌లను తొలగించాలా?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్‌లను తొలగించాలా?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్‌ను తొలగించాలా?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫోల్డర్‌లు మరియు వీటిలోని కంటెంట్‌లను తొలగించాలా?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫోల్డర్ మరియు దీనిలోని కంటెంట్‌లను తొలగించాలా?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> అంశాలను తొలగించాలా?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> అంశాన్ని తొలగించాలా?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 99009b4..491e984 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -119,11 +119,18 @@
       <item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
       <item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"ลบ \"<xliff:g id="NAME">%1$s</xliff:g>\" ไหม"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"ลบโฟลเดอร์ \"<xliff:g id="NAME">%1$s</xliff:g>\" และเนื้อหาข้างในไหม"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+      <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> โฟลเดอร์และเนื้อหาข้างในใช่ไหม</item>
+      <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> โฟลเดอร์และเนื้อหาข้างในใช่ไหม</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการใช่ไหม</item>
+      <item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการใช่ไหม</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index dd08e13..27d6671 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Gusto mo bang i-delete ang \"<xliff:g id="NAME">%1$s</xliff:g>?\""</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Gusto mo bang i-delete ang folder na \"<xliff:g id="NAME">%1$s</xliff:g>\" at ang mga content nito?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> (na) file?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> folder at mga content ng mga ito?</item>
+      <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na folder at mga content ng mga ito?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> item?</item>
+      <item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na item?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 3cc53e1..dda9f28 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" silinsin mi?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" adlı klasör ve içindekiler silinsin mi?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinsin mi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinsin mi?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> klasör ve içindekiler silinsin mi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> klasör ve içindekiler silinsin mi?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe silinsin mi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe silinsin mi?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index f9620a0..ec7e1d6 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -137,7 +137,22 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Видалити файл <xliff:g id="NAME">%1$s</xliff:g>?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Видалити папку \"<xliff:g id="NAME">%1$s</xliff:g>\" та її вміст?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файли?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлів?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлу?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папку та їх вміст?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папки та їх вміст?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папок та їх вміст?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> папки та їх вміст?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елемент?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елементи?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елементів?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> елемента?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 76d4cee..4ea9985 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"\"<xliff:g id="NAME">%1$s</xliff:g>\" حذف کریں؟"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"\"<xliff:g id="NAME">%1$s</xliff:g>\" فولڈر اور اس کی مشمولات حذف کریں؟"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف کریں؟</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف کریں؟</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فولڈرز اور ان کے مشمولات حذف کریں؟</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فولڈر اور اس کے مشمولات حذف کریں؟</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> آئٹمز حذف کریں؟</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> آئٹم حذف کریں؟</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 47f1ac1..dffbba5 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -111,7 +111,7 @@
     <string name="rename_error" msgid="4203041674883412606">"Hujjatni qayta nomlab bo‘lmadi"</string>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
     <string name="open_external_dialog_request" msgid="5789329484285817629">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasining <xliff:g id="STORAGE"><i>^3</i></xliff:g> xotirasidagi “<xliff:g id="DIRECTORY"><i>^2</i></xliff:g>” jildiga kirishiga ruxsat berilsinmi?"</string>
-    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasining <xliff:g id="STORAGE"><i>^2</i></xliff:g> xotirasidagi ma’lumotlardan, jumladan, rasmlar va videolardan foydalanishiga ruxsat berilsinmi?"</string>
+    <string name="open_external_dialog_root_request" msgid="8899108702926347720">"<xliff:g id="APPNAME"><b>^1</b></xliff:g> ilovasiga <xliff:g id="STORAGE"><i>^2</i></xliff:g> xotirasidagi ma’lumotlardan, jumladan, rasmlar va videolardan foydalanishiga ruxsat berilsinmi?"</string>
     <string name="never_ask_again" msgid="4295278542972859268">"Boshqa so‘ralmasin"</string>
     <string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
     <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
@@ -119,11 +119,18 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta belgilandi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta belgilandi</item>
     </plurals>
-    <!-- no translation found for delete_filename_confirmation_message (5312817725577537488) -->
-    <skip />
-    <!-- no translation found for delete_foldername_confirmation_message (5885501832257285329) -->
-    <skip />
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"“<xliff:g id="NAME">%1$s</xliff:g>” fayli o‘chirib tashlansinmi?"</string>
+    <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"“<xliff:g id="NAME">%1$s</xliff:g>” jildi ichidagi kontentlari bilan o‘chirib tashlansinmi?"</string>
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl o‘chirib tashlansinmi?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta jild ichidagi kontentlari bilan o‘chirib tashlansinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta jild ichidagi kontentlari bilan o‘chirib tashlansinmi?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta element o‘chirib tashlansinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta element o‘chirib tashlansinmi?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 613f271..127c2d3 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Xóa \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Xóa thư mục \"<xliff:g id="NAME">%1$s</xliff:g>\" và nội dung của thư mục?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp?</item>
+      <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> thư mục và nội dung trong đó?</item>
+      <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> thư mục và nội dung trong đó?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> mục?</item>
+      <item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> mục?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 3bfeaaf..45d22a3 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要删除“<xliff:g id="NAME">%1$s</xliff:g>”吗?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要删除文件夹“<xliff:g id="NAME">%1$s</xliff:g>”及其中的内容吗?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件?</item>
+      <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件夹及其中的内容?</item>
+      <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件夹及其中的内容?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 项?</item>
+      <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 项?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 7587086..08aefdd 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」資料夾及其內容嗎?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個資料夾及其內容嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個資料夾及其內容嗎?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目嗎?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 7f13098..90c932c 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」嗎?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"要刪除「<xliff:g id="NAME">%1$s</xliff:g>」資料夾和當中的內容嗎?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個資料夾和當中的內容嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個資料夾和當中的內容嗎?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目嗎?</item>
+      <item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目嗎?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 6453059..e83bb3d 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -121,7 +121,16 @@
     </plurals>
     <string name="delete_filename_confirmation_message" msgid="5312817725577537488">"Susa i-\"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string>
     <string name="delete_foldername_confirmation_message" msgid="5885501832257285329">"Susa ifolda engu-\"<xliff:g id="NAME">%1$s</xliff:g>\" nokuqukethwe kwalo?"</string>
-    <!-- no translation found for delete_files_confirmation_message (8417505791395471802) -->
-    <!-- no translation found for delete_folders_confirmation_message (9185648028213507769) -->
-    <!-- no translation found for delete_items_confirmation_message (5376214433530243459) -->
+    <plurals name="delete_files_confirmation_message" formatted="false" msgid="8417505791395471802">
+      <item quantity="one">Susa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="other">Susa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+    </plurals>
+    <plurals name="delete_folders_confirmation_message" formatted="false" msgid="9185648028213507769">
+      <item quantity="one">Susa amafolda angu-<xliff:g id="COUNT_1">%1$d</xliff:g> nokuqukethwe kwawo?</item>
+      <item quantity="other">Susa amafolda angu-<xliff:g id="COUNT_1">%1$d</xliff:g> nokuqukethwe kwawo?</item>
+    </plurals>
+    <plurals name="delete_items_confirmation_message" formatted="false" msgid="5376214433530243459">
+      <item quantity="one">Susa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="other">Susa izinto ezingu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index 765211d..6590bbe 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -24,8 +24,9 @@
     <!-- Indicates if the home directory should be hidden in the roots list, that is presented
          in the drawer/left side panel ) -->
     <bool name="home_root_hidden">true</bool>
-    <!-- Indicates if the advanced roots like internal storage should be hidden in the roots list) -->
-    <bool name="advanced_roots_hidden">true</bool>
+    <!-- Indicates if the advanced roots like internal storage should be shown in the roots list.
+         When enabled there is no menu option to toggle internal storage visibility. -->
+    <bool name="advanced_roots_shown">false</bool>
     <!-- Indicates if search view is taking the whole toolbar space -->
     <bool name="full_bar_search_view">true</bool>
 </resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index b26ee97..fb557ca 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -204,6 +204,9 @@
     <string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
         access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory on
         <xliff:g id="storage" example="SD Card"><i>^3</i></xliff:g>?</string>
+    <!-- Text in an alert dialog asking user to grant app access to a given directory in the internal storage -->
+    <string name="open_external_dialog_request_primary_volume">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
+        access to <xliff:g id="directory" example="Pictures"><i>^2</i></xliff:g> directory?</string>
     <!-- Text in an alert dialog asking user to grant app access to all data in an external storage volume -->
     <string name="open_external_dialog_root_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g>
         access to your data, including photos and videos, on <xliff:g id="storage" example="SD Card"><i>^2</i></xliff:g>?</string>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index b16554c..b0996aa 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -36,8 +36,6 @@
         <item name="android:windowActionBar">false</item>
         <item name="android:windowActionModeOverlay">true</item>
         <item name="android:windowNoTitle">true</item>
-        <item name="android:windowTranslucentStatus">true</item>
-        <item name="android:fitsSystemWindows">false</item>
 
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
     </style>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 69315f7..87136ef3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -18,6 +18,11 @@
 
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.EXTRA_BENCHMARK;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
 import static com.android.documentsui.State.MODE_GRID;
 
 import android.app.Activity;
@@ -44,6 +49,7 @@
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.WindowManager;
 import android.widget.Spinner;
 
 import com.android.documentsui.SearchViewManager.SearchManagerListener;
@@ -98,6 +104,16 @@
     @CallSuper
     @Override
     public void onCreate(Bundle icicle) {
+        // This flag is being set here as a result of the bug. When the flag was set in the
+        // styles.xml keyboard was messing the layout of dialogs (create dir, rename).
+        // Attempts were made to keep the flag in the main theme and to override it in the dialog
+        // layout xml or to create separate style for dialog and assign it in styles.xml.
+        // None of this brought successful results.
+        // Setting the flag works here most probably because of the timing when it is set. Also the
+        // setting might not affect the dialogs that are created in new windows or it affects them
+        // in the different way that having this in the style.
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
         // Record the time when onCreate is invoked for metric.
         mStartTime = new Date().getTime();
 
@@ -165,6 +181,7 @@
         final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
         final MenuItem grid = menu.findItem(R.id.menu_grid);
         final MenuItem list = menu.findItem(R.id.menu_list);
+        final MenuItem advanced = menu.findItem(R.id.menu_advanced);
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
 
         // Search uses backend ranking; no sorting, recents doesn't support sort.
@@ -176,6 +193,9 @@
         grid.setVisible(mState.derivedMode != State.MODE_GRID);
         list.setVisible(mState.derivedMode != State.MODE_LIST);
 
+        advanced.setVisible(mState.showAdvancedOption);
+        advanced.setTitle(mState.showAdvancedOption && mState.showAdvanced
+                ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
         fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
                 ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
 
@@ -195,25 +215,30 @@
             return state;
         }
 
-        State state = createSharedState();
-        includeState(state);
-        if (DEBUG) Log.d(mTag, "Created new state object: " + state);
-        return state;
-    }
-
-    private State createSharedState() {
         State state = new State();
 
         final Intent intent = getIntent();
 
         state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-
         state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
         state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
-
         state.initAcceptMimes(intent);
         state.excludedAuthorities = getExcludedAuthorities();
 
+        includeState(state);
+
+        // Advanced roots are shown by deafult without menu option if forced by config or intent.
+        state.showAdvanced = getResources().getBoolean(R.bool.advanced_roots_shown)
+                || intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+        // Menu option is shown for whitelisted intents if advanced roots are not shown by default.
+        state.showAdvancedOption = !state.showAdvanced &&
+                (state.action == ACTION_OPEN ||
+                        state.action == ACTION_CREATE ||
+                        state.action == ACTION_OPEN_TREE ||
+                        state.action == ACTION_GET_CONTENT);
+
+        if (DEBUG) Log.d(mTag, "Created new state object: " + state);
+
         return state;
     }
 
@@ -247,6 +272,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
+        Metrics.logMenuAction(this, item.getItemId());
 
         switch (item.getItemId()) {
             case android.R.id.home:
@@ -287,6 +313,10 @@
                 }
                 return true;
 
+            case R.id.menu_advanced:
+                setDisplayAdvancedDevices(!mState.showAdvanced);
+                return true;
+
             case R.id.menu_file_size:
                 setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this));
                 return true;
@@ -452,6 +482,12 @@
                 ? DocumentsContract.buildRootUri("com.android.providers.downloads.documents",
                         "downloads")
                 : DocumentsContract.buildHomeUri();
+            }
+
+    void setDisplayAdvancedDevices(boolean display) {
+        mState.showAdvanced = display;
+        RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
+        invalidateOptionsMenu();
     }
 
     void setDisplayFileSize(boolean display) {
@@ -600,10 +636,12 @@
                 return true;
             }
         } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+            Metrics.logKeyboardAction(this, keyCode);
             // Tab toggles focus on the navigation drawer.
             toggleNavDrawerFocus();
             return true;
         } else if (keyCode == KeyEvent.KEYCODE_DEL) {
+            Metrics.logKeyboardAction(this, keyCode);
             popDir();
             return true;
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index ebc9082..5b5a96e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -153,10 +153,12 @@
             if (result != null) {
                 // Navigate into newly created child
                 mActivity.onDirectoryCreated(result);
+                Metrics.logCreateDirOperation(getContext());
             } else {
-                Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
+                Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT)
+                        .show();
+                Metrics.logCreateDirError(getContext());
             }
-
             mActivity.setPending(false);
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
index 2dbb730..7a4099a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -18,6 +18,7 @@
 
 import static com.android.documentsui.Shared.DEBUG;
 
+import android.annotation.IntDef;
 import android.app.Activity;
 import android.content.Context;
 import android.support.v4.app.ActionBarDrawerToggle;
@@ -27,16 +28,44 @@
 import android.view.View;
 import android.widget.Toolbar;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A facade over the various pieces comprising "roots fragment in a Drawer".
  *
  * @see DrawerController#create(DrawerLayout)
  */
 abstract class DrawerController implements DrawerListener {
-
     public static final String TAG = "DrawerController";
 
+    // Drawer opening triggered by tapping the navigation icon
+    public static final int OPENED_HAMBURGER = 0;
+    // Drawer opening triggered by swiping right from the edge of the screen
+    public static final int OPENED_SWIPE = 1;
+    // Mostly programmatically forced drawer opening
+    public static final int OPENED_OTHER = 2;
+
+    @IntDef(flag = true, value = {
+            OPENED_HAMBURGER,
+            OPENED_SWIPE,
+            OPENED_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Trigger {}
+
+    /**
+     * Toggles the drawer and sets the OPENED_OTHER as the action that causes opening the drawer.
+     * @param open
+     */
     abstract void setOpen(boolean open);
+
+    /**
+     * Toggles the drawer.
+     * @param open
+     * @param trigger Indicates what action caused opening the drawer. It is ignored for closing.
+     */
+    abstract void setOpen(boolean open, @Trigger int trigger);
     abstract boolean isPresent();
     abstract boolean isOpen();
     abstract void setTitle(String title);
@@ -92,11 +121,11 @@
      * Runtime controller that manages a real drawer.
      */
     private static final class RuntimeDrawerController extends DrawerController {
-
         private final ActionBarDrawerToggle mToggle;
         private DrawerLayout mLayout;
         private View mDrawer;
         private Toolbar mToolbar;
+        private @Trigger int mTrigger = OPENED_OTHER;
 
         public RuntimeDrawerController(
                 DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
@@ -113,8 +142,14 @@
 
         @Override
         void setOpen(boolean open) {
+            setOpen(open, OPENED_OTHER);
+        }
+
+        @Override
+        void setOpen(boolean open, @Trigger int trigger) {
             if (open) {
                 mLayout.openDrawer(mDrawer);
+                mTrigger = trigger;
             } else {
                 mLayout.closeDrawer(mDrawer);
             }
@@ -148,16 +183,21 @@
         @Override
         public void onDrawerOpened(View drawerView) {
             mToggle.onDrawerOpened(drawerView);
+            Metrics.logDrawerOpened(mToolbar.getContext(), mTrigger);
         }
 
         @Override
         public void onDrawerClosed(View drawerView) {
             mToggle.onDrawerClosed(drawerView);
+            mTrigger = OPENED_OTHER;
         }
 
         @Override
         public void onDrawerStateChanged(int newState) {
             mToggle.onDrawerStateChanged(newState);
+            if (newState == DrawerLayout.STATE_DRAGGING) {
+                mTrigger = OPENED_SWIPE;
+            }
         }
     }
 
@@ -169,6 +209,8 @@
         @Override
         void setOpen(boolean open) {}
 
+        @Override
+        void setOpen(boolean open, @Trigger int trigger) {}
 
         @Override
         boolean isOpen() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 3e04e2a..d4439d8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -212,19 +212,22 @@
             case R.id.menu_create_dir:
                 assert(canCreateDirectory());
                 showCreateDirectoryDialog();
-                return true;
+                break;
             case R.id.menu_new_window:
                 createNewWindow();
-                return true;
+                break;
             case R.id.menu_paste_from_clipboard:
                 DirectoryFragment dir = getDirectoryFragment();
                 if (dir != null) {
                     dir.pasteFromClipboard();
                 }
-                return true;
+                break;
+            default:
+                return super.onOptionsItemSelected(item);
         }
 
-        return super.onOptionsItemSelected(item);
+        Metrics.logMenuAction(this, item.getItemId());
+        return true;
     }
 
     private void createNewWindow() {
@@ -235,7 +238,7 @@
         // With new multi-window mode we have to pick how we are launched.
         // By default we'd be launched in-place above the existing app.
         // By setting launch-to-side ActivityManager will open us to side.
-        if (inMultiWindow()) {
+        if (isInMultiWindowMode()) {
             intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
         }
 
@@ -346,18 +349,21 @@
             case KeyEvent.KEYCODE_A:
                 dir = getDirectoryFragment();
                 if (dir != null) {
+                    Metrics.logKeyboardAction(this, keyCode);
                     dir.selectAllFiles();
                 }
                 return true;
             case KeyEvent.KEYCODE_C:
                 dir = getDirectoryFragment();
                 if (dir != null) {
+                    Metrics.logKeyboardAction(this, keyCode);
                     dir.copySelectedToClipboard();
                 }
                 return true;
             case KeyEvent.KEYCODE_V:
                 dir = getDirectoryFragment();
                 if (dir != null) {
+                    Metrics.logKeyboardAction(this, keyCode);
                     dir.pasteFromClipboard();
                 }
                 return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index 7ad4a09..a4a67f9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -29,6 +29,7 @@
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.util.Log;
+import android.view.KeyEvent;
 
 import com.android.documentsui.State.ActionType;
 import com.android.documentsui.model.DocumentInfo;
@@ -66,6 +67,11 @@
     private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external";
     private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
     private static final String COUNT_STARTUP_MS = "docsui_startup_ms";
+    private static final String COUNT_DRAWER_OPENED = "docsui_drawer_opened";
+    private static final String COUNT_DRAG_N_DROP = "docsui_drag_n_drop";
+    private static final String COUNT_SEARCH = "docsui_search";
+    private static final String COUNT_MENU_ACTION = "docsui_menu_action";
+    private static final String COUNT_KEYBOARD_ACTION = "docsui_keyboard_action";
 
     // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
     // root that is not explicitly recognized by the Metrics code (see {@link
@@ -146,10 +152,14 @@
     private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 6; // Move to a system provider.
     private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 7; // Move to a 3rd-party provider.
     private static final int FILEOP_DELETE = 8;
+    private static final int FILEOP_RENAME = 9;
+    private static final int FILEOP_CREATE_DIR = 10;
     private static final int FILEOP_OTHER_ERROR = 100;
     private static final int FILEOP_DELETE_ERROR = 101;
     private static final int FILEOP_MOVE_ERROR = 102;
     private static final int FILEOP_COPY_ERROR = 103;
+    private static final int FILEOP_RENAME_ERROR = 104;
+    private static final int FILEOP_CREATE_DIR_ERROR = 105;
 
     @IntDef(flag = true, value = {
             FILEOP_OTHER,
@@ -160,10 +170,14 @@
             FILEOP_MOVE_SYSTEM_PROVIDER,
             FILEOP_MOVE_EXTERNAL_PROVIDER,
             FILEOP_DELETE,
+            FILEOP_RENAME,
+            FILEOP_CREATE_DIR,
             FILEOP_OTHER_ERROR,
             FILEOP_COPY_ERROR,
             FILEOP_MOVE_ERROR,
-            FILEOP_DELETE_ERROR
+            FILEOP_DELETE_ERROR,
+            FILEOP_RENAME_ERROR,
+            FILEOP_CREATE_DIR_ERROR
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FileOp {}
@@ -187,8 +201,71 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface MetricsOpType {}
 
-    // Codes representing different launch actions. These are used for bucketing stats in the
-    // COUNT_LAUNCH_ACTION histogram.
+    // Codes representing different provider types.  Used for sorting file operations when logging.
+    private static final int PROVIDER_INTRA = 0;
+    private static final int PROVIDER_SYSTEM = 1;
+    private static final int PROVIDER_EXTERNAL = 2;
+
+    @IntDef(flag = false, value = {
+            PROVIDER_INTRA,
+            PROVIDER_SYSTEM,
+            PROVIDER_EXTERNAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Provider {}
+
+
+    // Codes representing different menu actions. These are used for bucketing stats in the
+    // COUNT_MENU_ACTION histogram.
+    // Both regular toolbar menu and action mode menu operations are included.
+    // Do not change or rearrange these values, that will break historical data. Only add to the
+    // list.
+    // Do not use negative numbers or zero; clearcut only handles positive integers.
+    private static final int ACTION_MENU_OTHER = 1;
+    private static final int ACTION_MENU_GRID = 2;
+    private static final int ACTION_MENU_LIST = 3;
+    private static final int ACTION_MENU_SORT = 4;
+    private static final int ACTION_MENU_SORT_NAME = 5;
+    private static final int ACTION_MENU_SORT_DATE = 6;
+    private static final int ACTION_MENU_SORT_SIZE = 7;
+    private static final int ACTION_MENU_SEARCH = 8;
+    private static final int ACTION_MENU_SHOW_SIZE = 9;
+    private static final int ACTION_MENU_SETTINGS = 10;
+    private static final int ACTION_MENU_COPY_TO = 11;
+    private static final int ACTION_MENU_MOVE_TO = 12;
+    private static final int ACTION_MENU_DELETE = 13;
+    private static final int ACTION_MENU_RENAME = 14;
+    private static final int ACTION_MENU_CREATE_DIR = 15;
+    private static final int ACTION_MENU_SELECT_ALL = 16;
+    private static final int ACTION_MENU_SHARE = 17;
+    private static final int ACTION_MENU_OPEN = 18;
+    private static final int ACTION_MENU_ADVANCED = 19;
+
+    @IntDef(flag = false, value = {
+            ACTION_MENU_OTHER,
+            ACTION_MENU_GRID,
+            ACTION_MENU_LIST,
+            ACTION_MENU_SORT,
+            ACTION_MENU_SORT_NAME,
+            ACTION_MENU_SORT_DATE,
+            ACTION_MENU_SORT_SIZE,
+            ACTION_MENU_SHOW_SIZE,
+            ACTION_MENU_SETTINGS,
+            ACTION_MENU_COPY_TO,
+            ACTION_MENU_MOVE_TO,
+            ACTION_MENU_DELETE,
+            ACTION_MENU_RENAME,
+            ACTION_MENU_CREATE_DIR,
+            ACTION_MENU_SELECT_ALL,
+            ACTION_MENU_SHARE,
+            ACTION_MENU_OPEN,
+            ACTION_MENU_ADVANCED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MenuAction {}
+
+    // Codes representing different menu actions. These are used for bucketing stats in the
+    // COUNT_MENU_ACTION histogram.
     // Do not change or rearrange these values, that will break historical data. Only add to the
     // list.
     // Do not use negative numbers or zero; clearcut only handles positive integers.
@@ -214,18 +291,45 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface MetricsAction {}
 
-    // Codes representing different provider types.  Used for sorting file operations when logging.
-    private static final int PROVIDER_INTRA = 0;
-    private static final int PROVIDER_SYSTEM = 1;
-    private static final int PROVIDER_EXTERNAL = 2;
+    // Codes representing different keyboard shortcut triggered actions. These are used for
+    // bucketing stats in the COUNT_KEYBOARD_ACTION histogram.
+    // Do not change or rearrange these values, that will break historical data. Only add to the
+    // list.
+    // Do not use negative numbers or zero; clearcut only handles positive integers.
+    private static final int ACTION_KEYBOARD_OTHER = 1;
+    private static final int ACTION_KEYBOARD_PASTE = 2;
+    private static final int ACTION_KEYBOARD_COPY = 3;
+    private static final int ACTION_KEYBOARD_DELETE = 4;
+    private static final int ACTION_KEYBOARD_SELECT_ALL = 5;
+    private static final int ACTION_KEYBOARD_BACK = 6;
+    private static final int ACTION_KEYBOARD_SWITCH_FOCUS = 7;
 
-    @IntDef(flag = true, value = {
-            PROVIDER_INTRA,
-            PROVIDER_SYSTEM,
-            PROVIDER_EXTERNAL
+    @IntDef(flag = false, value = {
+            ACTION_KEYBOARD_OTHER,
+            ACTION_KEYBOARD_PASTE,
+            ACTION_KEYBOARD_COPY,
+            ACTION_KEYBOARD_DELETE,
+            ACTION_KEYBOARD_SELECT_ALL,
+            ACTION_KEYBOARD_BACK,
+            ACTION_KEYBOARD_SWITCH_FOCUS
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface Provider {}
+    public @interface KeyboardAction {}
+
+    // Codes representing different actions to open the drawer. They are used for bucketing stats in
+    // the COUNT_DRAWER_OPENED histogram.
+    // Do not change or rearrange these values, that will break historical data. Only add to the
+    // list.
+    // Do not use negative numbers or zero; clearcut only handles positive integers.
+    private static final int DRAWER_OPENED_HAMBURGER = 1;
+    private static final int DRAWER_OPENED_SWIPE = 2;
+
+    @IntDef(flag = true, value = {
+            DRAWER_OPENED_HAMBURGER,
+            DRAWER_OPENED_SWIPE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DrawerTrigger {}
 
     /**
      * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
@@ -287,6 +391,20 @@
     }
 
     /**
+     * Logs a drawer opened event. Call this when the user opens drawer by swipe or by clicking the
+     * hamburger icon.
+     * @param context
+     * @param trigger type of action that opened the drawer
+     */
+    public static void logDrawerOpened(Context context, @DrawerController.Trigger int trigger) {
+        if (trigger == DrawerController.OPENED_HAMBURGER) {
+            logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_HAMBURGER);
+        } else if (trigger == DrawerController.OPENED_SWIPE) {
+            logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_SWIPE);
+        }
+    }
+
+    /**
      * Logs file operation stats. Call this when a file operation has completed. The given
      * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one
      * provider to another vs copying within a given provider).  No PII is logged.
@@ -317,6 +435,28 @@
     }
 
     /**
+     * Logs create directory operation. It is a part of file operation stats. We do not
+     * differentiate between internal and external locations, all create directory operations are
+     * logged under COUNT_FILEOP_SYSTEM. Call this when a create directory operation has completed.
+     *
+     * @param context
+     */
+    public static void logCreateDirOperation(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
+    }
+
+    /**
+     * Logs rename file operation. It is a part of file operation stats. We do not differentiate
+     * between internal and external locations, all rename operations are logged under
+     * COUNT_FILEOP_SYSTEM. Call this when a rename file operation has completed.
+     *
+     * @param context
+     */
+    public static void logRenameFileOperation(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME);
+    }
+
+    /**
      * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete)
      * fails.
      *
@@ -349,6 +489,28 @@
     }
 
     /**
+     * Logs create directory operation error. We do not differentiate between internal and external
+     * locations, all create directory errors are logged under COUNT_FILEOP_SYSTEM. Call this when a
+     * create directory operation fails.
+     *
+     * @param context
+     */
+    public static void logCreateDirError(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
+    }
+
+    /**
+     * Logs rename file operation error. We do not differentiate between internal and external
+     * locations, all rename errors are logged under COUNT_FILEOP_SYSTEM. Call this
+     * when a rename file operation fails.
+     *
+     * @param context
+     */
+    public static void logRenameFileError(Context context) {
+        logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME_ERROR);
+    }
+
+    /**
      * Logs the cancellation of a file operation.  Call this when a Job is canceled.
      * @param context
      * @param operationType
@@ -358,6 +520,39 @@
     }
 
     /**
+     * Logs keyboard shortcut actions. Since keyboard shortcuts have their corresponding menu items,
+     * they are identified by menu item resource id for convenience.
+     * @param context
+     * @param keyCode
+     */
+    public static void logKeyboardAction(Context context, int keyCode) {
+        @KeyboardAction int keyboardAction = ACTION_KEYBOARD_OTHER;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_V:
+                keyboardAction = ACTION_KEYBOARD_PASTE;
+                break;
+            case KeyEvent.KEYCODE_C:
+                keyboardAction = ACTION_KEYBOARD_COPY;
+                break;
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                keyboardAction = ACTION_KEYBOARD_DELETE;
+                break;
+            case KeyEvent.KEYCODE_A:
+                keyboardAction = ACTION_KEYBOARD_SELECT_ALL;
+                break;
+            case KeyEvent.KEYCODE_DEL:
+                keyboardAction = ACTION_KEYBOARD_BACK;
+                break;
+            case KeyEvent.KEYCODE_TAB:
+                keyboardAction = ACTION_KEYBOARD_SWITCH_FOCUS;
+                break;
+            default:
+                break;
+        }
+        logHistogram(context, COUNT_KEYBOARD_ACTION, keyboardAction);
+    }
+
+    /**
      * Logs startup time in milliseconds.
      * @param context
      * @param startupMs Startup time in milliseconds.
@@ -366,6 +561,25 @@
         logHistogram(context, COUNT_STARTUP_MS, startupMs);
     }
 
+    /**
+     * Logs a drag and drop action. Call this when the user drops the content triggering copy.
+     * operation.
+     *
+     * @param context
+     */
+    public static void logDragNDrop(Context context) {
+        logCount(context, COUNT_DRAG_N_DROP);
+    }
+
+    /**
+     * Logs a search. Call this when the search operation is finished.
+     *
+     * @param context
+     */
+    public static void logSearch(Context context) {
+        logCount(context, COUNT_SEARCH);
+    }
+
     private static void logInterProviderFileOps(
             Context context,
             String histogram,
@@ -486,6 +700,74 @@
     }
 
     /**
+     * Logs menu action that was selected by user.
+     * @param context
+     * @param id Resource id of the menu item.
+     */
+    public static void logMenuAction(Context context, int id) {
+        @MenuAction int menuAction = ACTION_MENU_OTHER;
+        switch (id) {
+            case R.id.menu_grid:
+                menuAction = ACTION_MENU_GRID;
+                break;
+            case R.id.menu_list:
+                menuAction = ACTION_MENU_LIST;
+                break;
+            case R.id.menu_sort:
+                menuAction = ACTION_MENU_SORT;
+                break;
+            case R.id.menu_sort_name:
+                menuAction = ACTION_MENU_SORT_NAME;
+                break;
+            case R.id.menu_sort_date:
+                menuAction = ACTION_MENU_SORT_DATE;
+                break;
+            case R.id.menu_sort_size:
+                menuAction = ACTION_MENU_SORT_SIZE;
+                break;
+            case R.id.menu_search:
+                menuAction = ACTION_MENU_SEARCH;
+                break;
+            case R.id.menu_file_size:
+                menuAction = ACTION_MENU_SHOW_SIZE;
+                break;
+            case R.id.menu_settings:
+                menuAction = ACTION_MENU_SETTINGS;
+                break;
+            case R.id.menu_copy_to:
+                menuAction = ACTION_MENU_COPY_TO;
+                break;
+            case R.id.menu_move_to:
+                menuAction = ACTION_MENU_MOVE_TO;
+                break;
+            case R.id.menu_delete:
+                menuAction = ACTION_MENU_DELETE;
+                break;
+            case R.id.menu_rename:
+                menuAction = ACTION_MENU_RENAME;
+                break;
+            case R.id.menu_create_dir:
+                menuAction = ACTION_MENU_CREATE_DIR;
+                break;
+            case R.id.menu_select_all:
+                menuAction = ACTION_MENU_SELECT_ALL;
+                break;
+            case R.id.menu_share:
+                menuAction = ACTION_MENU_SHARE;
+                break;
+            case R.id.menu_open:
+                menuAction = ACTION_MENU_OPEN;
+                break;
+            case R.id.menu_advanced:
+                menuAction = ACTION_MENU_ADVANCED;
+                break;
+            default:
+                break;
+        }
+        logHistogram(context, COUNT_MENU_ACTION, menuAction);
+    }
+
+    /**
      * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
      *
      * @param context
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index 30c1020..f6fe47b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -91,7 +91,7 @@
 
     private void onNavigationIconClicked() {
         if (mDrawer.isPresent()) {
-            mDrawer.setOpen(true);
+            mDrawer.setOpen(true, DrawerController.OPENED_HAMBURGER);
         }
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index 2fe2756..854be0b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -86,6 +86,7 @@
     private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL";
     private static final String EXTRA_VOLUME_UUID = "com.android.documentsui.VOLUME_UUID";
     private static final String EXTRA_IS_ROOT = "com.android.documentsui.IS_ROOT";
+    private static final String EXTRA_IS_PRIMARY = "com.android.documentsui.IS_PRIMARY";
     // Special directory name representing the full volume
     static final String DIRECTORY_ROOT = "ROOT_DIRECTORY";
 
@@ -157,6 +158,13 @@
             Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory "
                     + directoryName + ", and user " + userId);
         final boolean isRoot = directoryName.equals(DIRECTORY_ROOT);
+        final boolean isPrimary = storageVolume.isPrimary();
+
+        if (isRoot && isPrimary) {
+            if (DEBUG) Log.d(TAG, "root access requested on primary volume");
+            return false;
+        }
+
         final File volumeRoot = storageVolume.getPathFile();
         File file;
         try {
@@ -235,6 +243,7 @@
         args.putString(EXTRA_VOLUME_UUID, volumeUuid);
         args.putString(EXTRA_APP_LABEL, appLabel);
         args.putBoolean(EXTRA_IS_ROOT, isRoot);
+        args.putBoolean(EXTRA_IS_PRIMARY, isPrimary);
 
         final FragmentManager fm = activity.getFragmentManager();
         final FragmentTransaction ft = fm.beginTransaction();
@@ -352,6 +361,7 @@
         private String mVolumeLabel;
         private String mAppLabel;
         private boolean mIsRoot;
+        private boolean mIsPrimary;
         private CheckBox mDontAskAgain;
         private OpenExternalDirectoryActivity mActivity;
         private AlertDialog mDialog;
@@ -367,6 +377,7 @@
                 mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
                 mAppLabel = args.getString(EXTRA_APP_LABEL);
                 mIsRoot = args.getBoolean(EXTRA_IS_ROOT);
+                mIsPrimary= args.getBoolean(EXTRA_IS_PRIMARY);
             }
             mActivity = (OpenExternalDirectoryActivity) getActivity();
         }
@@ -435,7 +446,9 @@
                 message = TextUtils.expandTemplate(getText(
                         R.string.open_external_dialog_root_request), mAppLabel, mVolumeLabel);
             } else {
-                message = TextUtils.expandTemplate(getText(R.string.open_external_dialog_request),
+                message = TextUtils.expandTemplate(
+                        getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
+                                : R.string.open_external_dialog_request),
                         mAppLabel, directory, mVolumeLabel);
             }
             final TextView messageField = (TextView) view.findViewById(R.id.message);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 6efe9c8..09fadc9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -65,8 +65,6 @@
 
     private static final String TAG = "RootsCache";
 
-    private static final boolean ENABLE_SYSTEM_CACHE = true;
-
     private final Context mContext;
     private final ContentObserver mObserver;
     private OnCacheUpdateListener mCacheUpdateListener;
@@ -200,7 +198,7 @@
         synchronized (mLock) {
             for (String authority : mStoppedAuthorities) {
                 if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
-                mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+                mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
             }
             mStoppedAuthorities.clear();
         }
@@ -219,13 +217,13 @@
             if (DEBUG) {
                 Log.d(TAG, "Loading stopped authority " + authority);
             }
-            mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
+            mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
             mStoppedAuthorities.remove(authority);
         }
     }
 
     private class UpdateTask extends AsyncTask<Void, Void, Void> {
-        private final String mFilterPackage;
+        private final String mForceRefreshPackage;
 
         private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
         private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
@@ -238,18 +236,18 @@
         }
 
         /**
-         * Only update roots belonging to given package name. Other roots will
+         * Force update roots belonging to given package name. Other roots will
          * be copied from cached {@link #mRoots} values.
          */
-        public UpdateTask(String filterPackage) {
-            mFilterPackage = filterPackage;
+        public UpdateTask(String forceRefreshPackage) {
+            mForceRefreshPackage = forceRefreshPackage;
         }
 
         @Override
         protected Void doInBackground(Void... params) {
             final long start = SystemClock.elapsedRealtime();
 
-            if (mFilterPackage != null) {
+            if (mForceRefreshPackage != null) {
                 // We must have previously cached values to fill in non-matching
                 // packages, so wait around for successful first load.
                 if (!waitForFirstLoad()) {
@@ -302,29 +300,17 @@
                 return;
             }
 
-            // Try using cached roots if filtering
-            boolean cacheHit = false;
-            if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
-                synchronized (mLock) {
-                    if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
-                        if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority);
-                        cacheHit = true;
-                    }
-                }
-            }
-
-            // Cache miss, or loading everything
-            if (!cacheHit) {
-                mTaskRoots.putAll(info.authority,
-                        loadRootsForAuthority(mContext.getContentResolver(), info.authority));
-            }
+            final boolean forceRefresh = Objects.equals(mForceRefreshPackage, info.packageName);
+            mTaskRoots.putAll(info.authority, loadRootsForAuthority(mContext.getContentResolver(),
+                    info.authority, forceRefresh));
         }
     }
 
     /**
      * Bring up requested provider and query for all active roots.
      */
-    private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) {
+    private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority,
+            boolean forceRefresh) {
         if (DEBUG) Log.d(TAG, "Loading roots for " + authority);
 
         synchronized (mObservedAuthorities) {
@@ -336,7 +322,7 @@
         }
 
         final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
-        if (ENABLE_SYSTEM_CACHE) {
+        if (!forceRefresh) {
             // Look for roots data that we might have cached for ourselves in the
             // long-lived system process.
             final Bundle systemCache = resolver.getCache(rootsUri);
@@ -363,14 +349,12 @@
             ContentProviderClient.releaseQuietly(client);
         }
 
-        if (ENABLE_SYSTEM_CACHE) {
-            // Cache these freshly parsed roots over in the long-lived system
-            // process, in case our process goes away. The system takes care of
-            // invalidating the cache if the package or Uri changes.
-            final Bundle systemCache = new Bundle();
-            systemCache.putParcelableArrayList(TAG, roots);
-            resolver.putCache(rootsUri, systemCache);
-        }
+        // Cache these freshly parsed roots over in the long-lived system
+        // process, in case our process goes away. The system takes care of
+        // invalidating the cache if the package or Uri changes.
+        final Bundle systemCache = new Bundle();
+        systemCache.putParcelableArrayList(TAG, roots);
+        resolver.putCache(rootsUri, systemCache);
 
         return roots;
     }
@@ -384,8 +368,8 @@
         synchronized (mLock) {
             RootInfo root = getRootLocked(authority, rootId);
             if (root == null) {
-                mRoots.putAll(
-                        authority, loadRootsForAuthority(mContext.getContentResolver(), authority));
+                mRoots.putAll(authority,
+                        loadRootsForAuthority(mContext.getContentResolver(), authority, false));
                 root = getRootLocked(authority, rootId);
             }
             return root;
@@ -493,6 +477,11 @@
                 continue;
             }
 
+            if (!state.showAdvanced && root.isAdvanced()) {
+                if (DEBUG) Log.d(TAG, "Excluding root because: unwanted advanced device.");
+                continue;
+            }
+
             if (state.localOnly && !root.isLocalOnly()) {
                 if (DEBUG) Log.d(TAG, "Excluding root because: unwanted non-local device.");
                 continue;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 8b4f40e..5f665c0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -321,9 +321,6 @@
 
                 if (root.isHome() && Shared.isHomeRootHidden(context)) {
                     continue;
-                } else if (root.isAdvanced()
-                        && Shared.areAdvancedRootsHidden(context, state)) {
-                    continue;
                 } else if (root.isLibrary()) {
                     if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
                     libraries.add(item);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
index 11b8891..945ed34 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
@@ -185,6 +185,9 @@
         if(mFullBar) {
             Menu menu = mActionBar.getMenu();
             menu.setGroupVisible(R.id.group_hide_when_searching, false);
+        } else {
+            // If search in full-bar mode it will be logged in FilesActivity#onOptionsItemSelected
+            Metrics.logMenuAction(mActionBar.getContext(), R.id.menu_search);
         }
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 655359a..2c60d4a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -181,12 +181,4 @@
         return context.getResources().getBoolean(R.bool.home_root_hidden);
     }
 
-    /*
-     * Indicates if the advanced roots should be hidden.
-     */
-    public static boolean areAdvancedRootsHidden(Context context, State state) {
-        return context.getResources().getBoolean(R.bool.advanced_roots_hidden)
-                && state.action != ACTION_OPEN_TREE;
-    }
-
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 534a483..c7d60e3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -93,6 +93,8 @@
     public boolean forceSize;
     public boolean showSize;
     public boolean localOnly;
+    public boolean showAdvancedOption;
+    public boolean showAdvanced;
     public boolean restored;
     /*
      * Indicates handler was an external app, like photos.
@@ -194,6 +196,8 @@
         out.writeInt(forceSize ? 1 : 0);
         out.writeInt(showSize ? 1 : 0);
         out.writeInt(localOnly ? 1 : 0);
+        out.writeInt(showAdvancedOption ? 1 : 0);
+        out.writeInt(showAdvanced ? 1 : 0);
         out.writeInt(restored ? 1 : 0);
         out.writeInt(external ? 1 : 0);
         DurableUtils.writeToParcel(out, stack);
@@ -223,6 +227,8 @@
             state.forceSize = in.readInt() != 0;
             state.showSize = in.readInt() != 0;
             state.localOnly = in.readInt() != 0;
+            state.showAdvancedOption = in.readInt() != 0;
+            state.showAdvanced = in.readInt() != 0;
             state.restored = in.readInt() != 0;
             state.external = in.readInt() != 0;
             DurableUtils.readFromParcel(in, state.stack);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 4acf85e..20316ff 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -85,6 +85,7 @@
 import com.android.documentsui.Events.MotionInputEvent;
 import com.android.documentsui.Menus;
 import com.android.documentsui.MessageBar;
+import com.android.documentsui.Metrics;
 import com.android.documentsui.R;
 import com.android.documentsui.RecentsLoader;
 import com.android.documentsui.RootsCache;
@@ -594,6 +595,7 @@
 
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            Metrics.logMenuAction(getContext(), item.getItemId());
 
             Selection selection = mSelectionManager.getSelection(new Selection());
 
@@ -1084,7 +1086,7 @@
         }
 
         // Make all items draggable.
-        view.setOnLongClickListener(mDragHelper);
+        view.setOnLongClickListener(onLongClickListener);
     }
 
     private View.OnDragListener mOnDragListener = new View.OnDragListener() {
@@ -1124,6 +1126,7 @@
                     if (Objects.equals(src, dst)) {
                         return false;
                     }
+                    Metrics.logDragNDrop(getContext());
                     copyFromClipData(event.getClipData(), dst);
                     return true;
             }
@@ -1336,6 +1339,7 @@
                     // This has to be handled here instead of in a keyboard shortcut, because
                     // keyboard shortcuts all have to be modified with the 'Ctrl' key.
                     if (mSelectionManager.hasSelection()) {
+                        Metrics.logKeyboardAction(getContext(), keyCode);
                         deleteDocuments(mSelectionManager.getSelection());
                     }
                     // Always handle the key, even if there was nothing to delete. This is a
@@ -1387,9 +1391,10 @@
         }
     }
 
-    private DragStartHelper mDragHelper = new DragStartHelper(null) {
+    private DragStartHelper.OnDragStartListener mOnDragStartListener =
+            new DragStartHelper.OnDragStartListener() {
         @Override
-        protected boolean onDragStart(View v) {
+        public boolean onDragStart(View v, DragStartHelper helper) {
             if (isSelected(getModelId(v))) {
                 List<DocumentInfo> docs = getDraggableDocuments(v);
                 if (docs.isEmpty()) {
@@ -1409,6 +1414,15 @@
         }
     };
 
+    private DragStartHelper mDragHelper = new DragStartHelper(null, mOnDragStartListener);
+
+    private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
+        @Override
+        public boolean onLongClick(View v) {
+            return mDragHelper.onLongClick(v);
+        }
+    };
+
     // Previously we listened to events with one class, only to bounce them forward
     // to GestureDetector. We're still doing that here, but with a single class
     // that reduces overall complexity in our glue code.
@@ -1439,7 +1453,7 @@
 
             // Detect drag events. When a drag is detected, intercept the rest of the gesture.
             View itemView = rv.findChildViewUnder(e.getX(), e.getY());
-            if (itemView != null && mDragHelper.handleTouch(itemView,  e)) {
+            if (itemView != null && mDragHelper.onTouch(itemView,  e)) {
                 return true;
             }
             // Forward unhandled events to the GestureDetector.
@@ -1451,7 +1465,7 @@
         @Override
         public void onTouchEvent(RecyclerView rv, MotionEvent e) {
             View itemView = rv.findChildViewUnder(e.getX(), e.getY());
-            mDragHelper.handleTouch(itemView,  e);
+            mDragHelper.onTouch(itemView,  e);
             // Note: even though this event is being handled as part of a drag gesture, continue
             // forwarding to the GestureDetector. The detector needs to see the entire cluster of
             // events in order to properly interpret gestures.
@@ -1612,6 +1626,9 @@
     @Override
     public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
         if (!isAdded()) return;
+        if (mSearchMode) {
+            Metrics.logSearch(getContext());
+        }
 
         State state = getDisplayState();
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 884abbb..73aa366 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -44,6 +44,7 @@
 
 import com.android.documentsui.BaseActivity;
 import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.Metrics;
 import com.android.documentsui.R;
 import com.android.documentsui.Shared;
 import com.android.documentsui.Snackbars;
@@ -227,11 +228,13 @@
 
         @Override
         protected void onPostExecute(DocumentInfo result) {
-            if (result == null) {
+            if (result != null) {
+                Metrics.logRenameFileOperation(getContext());
+            } else {
                 Snackbars.makeSnackbar(mActivity, R.string.rename_error, Snackbar.LENGTH_SHORT)
                         .show();
+                Metrics.logRenameFileError(getContext());
             }
-
             mActivity.setPending(false);
         }
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index e73dd8c..2e81545 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -55,6 +55,7 @@
 
         mState = new State();
         mState.action = State.ACTION_OPEN;
+        mState.showAdvanced = true;
         mState.localOnly = false;
     }
 
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
index 5b53caf..4c8dc00 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
@@ -162,7 +162,9 @@
     }
 
     UiObject findSearchViewIcon() {
-        return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
+        return mContext.getResources().getBoolean(R.bool.full_bar_search_view)
+                ? findObject("com.android.documentsui:id/menu_search")
+                : findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
     }
 
     UiObject findActionModeBar() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index b1d42e7..a7e4e12 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -464,7 +464,7 @@
         return 0;
     }
 
-    private int getLayoutIdFor(SecurityMode securityMode) {
+    protected int getLayoutIdFor(SecurityMode securityMode) {
         switch (securityMode) {
             case Pattern: return R.layout.keyguard_pattern_view;
             case PIN: return R.layout.keyguard_pin_view;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 454221a..2b549f1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -77,6 +77,7 @@
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
                 return SecurityMode.Password;
 
             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
diff --git a/packages/PrintServiceRecommendationService/Android.mk b/packages/PrintServiceRecommendationService/Android.mk
new file mode 100644
index 0000000..66cb057
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/Android.mk
@@ -0,0 +1,29 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := PrintRecommendationService
+
+include $(BUILD_PACKAGE)
+
+LOCAL_SDK_VERSION := system_current
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintServiceRecommendationService/AndroidManifest.xml b/packages/PrintServiceRecommendationService/AndroidManifest.xml
new file mode 100644
index 0000000..0eb218c
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.printservice.recommendation">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:allowClearUserData="false"
+        android:label="@string/app_label"
+        android:allowBackup= "false">
+
+        <service
+            android:name=".RecommendationServiceImpl"
+            android:permission="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE">
+
+            <intent-filter>
+                <action android:name="android.printservice.recommendation.RecommendationService" />
+            </intent-filter>
+        </service>
+
+    </application>
+
+</manifest>
diff --git a/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2 b/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/MODULE_LICENSE_APACHE2
diff --git a/packages/PrintServiceRecommendationService/NOTICE b/packages/PrintServiceRecommendationService/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/packages/PrintServiceRecommendationService/res/values/donottranslate.xml b/packages/PrintServiceRecommendationService/res/values/donottranslate.xml
new file mode 100644
index 0000000..4cf0eaf
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/values/donottranslate.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<resources>
+    <string name="app_label">Print Service Recommendation Service</string>
+</resources>
diff --git a/packages/PrintServiceRecommendationService/res/values/strings.xml b/packages/PrintServiceRecommendationService/res/values/strings.xml
new file mode 100644
index 0000000..83d3800
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  (c) Copyright 2016 Mopria Alliance, Inc.
+  (c) 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.
+-->
+
+<resources>
+    <string name="plugin_vendor_hp">HP</string>
+    <string name="plugin_vendor_lexmark">Lexmark</string>
+    <string name="plugin_vendor_brother">Brother</string>
+    <string name="plugin_vendor_canon">Canon</string>
+    <string name="plugin_vendor_xerox">Xerox</string>
+    <string name="plugin_vendor_samsung">Samsung Electorics</string>
+    <string name="plugin_vendor_epson">Epson</string>
+    <string name="plugin_vendor_konika_minolta">Konika Minolta</string>
+    <string name="plugin_vendor_fuji">Fuji</string>
+</resources>
diff --git a/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
new file mode 100644
index 0000000..fda2768
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/res/xml/vendorconfigs.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  (c) 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.
+  -->
+
+<vendors>
+    <vendor>
+        <name>@string/plugin_vendor_hp</name>
+        <package>com.hp.android.printservice</package>
+        <mdns-names>
+            <mdns-name>HP</mdns-name>
+            <mdns-name>Hewlett-Packard</mdns-name>
+            <mdns-name>Hewlett Packard</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_lexmark</name>
+        <package>com.lexmark.print.plugin</package>
+        <mdns-names>
+            <mdns-name>Lexmark</mdns-name>
+            <mdns-name>Lexmark International</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_brother</name>
+        <package>com.brother.printservice</package>
+        <mdns-names>
+            <mdns-name>Brother</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_canon</name>
+        <package>com.xerox.printservice</package>
+        <mdns-names>
+            <mdns-name>Canon</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_xerox</name>
+        <package>jp.co.canon.android.printservice.plugin</package>
+        <mdns-names>
+            <mdns-name>Xerox</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_samsung</name>
+        <package>com.sec.app.samsungprintservice</package>
+        <mdns-names>
+            <mdns-name>Samsung</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_epson</name>
+        <package>com.epson.mobilephone.android.epsonprintserviceplugin</package>
+        <mdns-names>
+            <mdns-name>Epson</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_konika_minolta</name>
+        <package>com.kmbt.printservice</package>
+        <mdns-names>
+            <mdns-name>kmkmkm</mdns-name>
+            <mdns-name>Konica Minolta</mdns-name>
+            <mdns-name>Minolta</mdns-name>
+        </mdns-names>
+    </vendor>
+
+    <vendor>
+        <name>@string/plugin_vendor_fuji</name>
+        <package>jp.co.fujixerox.prt.PrintUtil.PCL</package>
+        <mdns-names>
+            <mdns-name>FUJI XEROX</mdns-name>
+        </mdns-names>
+    </vendor>
+</vendors>
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
new file mode 100644
index 0000000..d604ef8
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/PrintServicePlugin.java
@@ -0,0 +1,75 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+
+/**
+ * Interface to be implemented by each print service plugin.
+ * <p/>
+ * A print service plugin is a minimal version of a real {@link android.printservice.PrintService
+ * print service}. You cannot print using the plugin. The only functionality in the plugin is to
+ * report the number of printers that the real service would discover.
+ */
+public interface PrintServicePlugin {
+    /**
+     * Call back used by the print service plugins.
+     */
+    interface PrinterDiscoveryCallback {
+        /**
+         * Announce that something changed and the UI for this plugin should be updated.
+         *
+         * @param numDiscoveredPrinters The number of printers discovered.
+         */
+        void onChanged(@IntRange(from = 0) int numDiscoveredPrinters);
+    }
+
+    /**
+     * Get the name (a string reference) of the {@link android.printservice.PrintService print
+     * service} with the {@link #getPackageName specified package name}. This is read once, hence
+     * returning different data at different times is not allowed.
+     *
+     * @return The name of the print service as a string reference. The localization is handled
+     *         outside of the plugin.
+     */
+    @StringRes int getName();
+
+    /**
+     * The package name of the full print service.
+     *
+     * @return The package name
+     */
+    @NonNull CharSequence getPackageName();
+
+    /**
+     * Start the discovery plugin.
+     *
+     * @param callback Callbacks used by this plugin.
+     *
+     * @throws Exception If anything went wrong when starting the plugin
+     */
+    void start(@NonNull PrinterDiscoveryCallback callback) throws Exception;
+
+    /**
+     * Stop the plugin. This can only return once the plugin is completely finished and cleaned up.
+     *
+     * @throws Exception If anything went wrong while stopping plugin
+     */
+    void stop() throws Exception;
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
new file mode 100644
index 0000000..9f6dad8
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -0,0 +1,110 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.content.res.Configuration;
+import android.printservice.recommendation.RecommendationInfo;
+import android.printservice.recommendation.RecommendationService;
+import android.printservice.PrintService;
+import android.util.Log;
+import com.android.printservice.recommendation.plugin.mdnsFilter.MDNSFilterPlugin;
+import com.android.printservice.recommendation.plugin.mdnsFilter.VendorConfig;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Service that recommends {@link PrintService print services} that might be a good idea to install.
+ */
+public class RecommendationServiceImpl extends RecommendationService
+        implements RemotePrintServicePlugin.OnChangedListener {
+    private static final String LOG_TAG = "PrintServiceRecService";
+
+    /** All registered plugins */
+    private ArrayList<RemotePrintServicePlugin> mPlugins;
+
+    @Override
+    public void onConnected() {
+        mPlugins = new ArrayList<>();
+
+        try {
+            for (VendorConfig config : VendorConfig.getAllConfigs(this)) {
+                try {
+                    mPlugins.add(new RemotePrintServicePlugin(new MDNSFilterPlugin(this,
+                            config.name, config.packageName, config.mDNSNames), this, false));
+                } catch (Exception e) {
+                    Log.e(LOG_TAG, "Could not initiate simple MDNS plugin for " +
+                            config.packageName, e);
+                }
+            }
+        } catch (IOException | XmlPullParserException e) {
+            new RuntimeException("Could not parse vendorconfig", e);
+        }
+
+        final int numPlugins = mPlugins.size();
+        for (int i = 0; i < numPlugins; i++) {
+            try {
+                mPlugins.get(i).start();
+            } catch (RemotePrintServicePlugin.PluginException e) {
+                Log.e(LOG_TAG, "Could not start plugin", e);
+            }
+        }
+    }
+
+    @Override
+    public void onDisconnected() {
+        final int numPlugins = mPlugins.size();
+        for (int i = 0; i < numPlugins; i++) {
+            try {
+                mPlugins.get(i).stop();
+            } catch (RemotePrintServicePlugin.PluginException e) {
+                Log.e(LOG_TAG, "Could not stop plugin", e);
+            }
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Need to update plugin names as they might be localized
+        onChanged();
+    }
+
+    @Override
+    public void onChanged() {
+        ArrayList<RecommendationInfo> recommendations = new ArrayList<>();
+
+        final int numPlugins = mPlugins.size();
+        for (int i = 0; i < numPlugins; i++) {
+            RemotePrintServicePlugin plugin = mPlugins.get(i);
+
+            try {
+                int numPrinters = plugin.getNumPrinters();
+
+                if (numPrinters > 0) {
+                    recommendations.add(new RecommendationInfo(plugin.packageName,
+                            getString(plugin.name), numPrinters,
+                            plugin.recommendsMultiVendorService));
+                }
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Could not read state of plugin for " + plugin.packageName, e);
+            }
+        }
+
+        updateRecommendations(recommendations);
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
new file mode 100644
index 0000000..dbd1649
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/RemotePrintServicePlugin.java
@@ -0,0 +1,152 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Wrapper for a {@link PrintServicePlugin}, isolating issues with the plugin as good as possible
+ * from the {@link RecommendationServiceImpl service}.
+ */
+class RemotePrintServicePlugin implements PrintServicePlugin.PrinterDiscoveryCallback {
+    /** Lock for this object */
+    private final Object mLock = new Object();
+
+    /** The name of the print service. */
+    public final @StringRes int name;
+
+    /** If the print service if for more than a single vendor */
+    public final boolean recommendsMultiVendorService;
+
+    /** The package name of the full print service */
+    public final @NonNull CharSequence packageName;
+
+    /** Wrapped plugin */
+    private final @NonNull PrintServicePlugin mPlugin;
+
+    /** The number of printers discovered by the plugin */
+    private @IntRange(from = 0) int mNumPrinters;
+
+    /** If the plugin is started by not yet stopped */
+    private boolean isRunning;
+
+    /** Listener for changes to {@link #mNumPrinters}. */
+    private @NonNull OnChangedListener mListener;
+
+    /**
+     * Create a new remote for a {@link PrintServicePlugin plugin}.
+     *
+     * @param plugin                       The plugin to be wrapped
+     * @param listener                     The listener to be notified about changes in this plugin
+     * @param recommendsMultiVendorService If the plugin detects printers of more than a single
+     *                                     vendor
+     *
+     * @throws PluginException If the plugin has issues while caching basic stub properties
+     */
+    public RemotePrintServicePlugin(@NonNull PrintServicePlugin plugin,
+            @NonNull OnChangedListener listener, boolean recommendsMultiVendorService)
+            throws PluginException {
+        mListener = listener;
+        mPlugin = plugin;
+        this.recommendsMultiVendorService = recommendsMultiVendorService;
+
+        // We handle any throwable to isolate our self from bugs in the plugin code.
+        // Cache simple properties to avoid having to deal with exceptions later in the code.
+        try {
+            name = Preconditions.checkArgumentPositive(mPlugin.getName(), "name");
+            packageName = Preconditions.checkStringNotEmpty(mPlugin.getPackageName(),
+                    "packageName");
+        } catch (Throwable e) {
+            throw new PluginException(mPlugin, "Cannot cache simple properties ", e);
+        }
+
+        isRunning = false;
+    }
+
+    /**
+     * Start the plugin. From now on there might be callbacks to the registered listener.
+     */
+    public void start()
+            throws PluginException {
+        // We handle any throwable to isolate our self from bugs in the stub code
+        try {
+            synchronized (mLock) {
+                isRunning = true;
+                mPlugin.start(this);
+            }
+        } catch (Throwable e) {
+            throw new PluginException(mPlugin, "Cannot start", e);
+        }
+    }
+
+    /**
+     * Stop the plugin. From this call on there will not be any more callbacks.
+     */
+    public void stop() throws PluginException {
+        // We handle any throwable to isolate our self from bugs in the stub code
+        try {
+            synchronized (mLock) {
+                mPlugin.stop();
+                isRunning = false;
+            }
+        } catch (Throwable e) {
+            throw new PluginException(mPlugin, "Cannot stop", e);
+        }
+    }
+
+    /**
+     * Get the current number of printers reported by the stub.
+     *
+     * @return The number of printers reported by the stub.
+     */
+    public @IntRange(from = 0) int getNumPrinters() {
+        return mNumPrinters;
+    }
+
+    @Override
+    public void onChanged(@IntRange(from = 0) int numDiscoveredPrinters) {
+        synchronized (mLock) {
+            Preconditions.checkState(isRunning);
+
+            mNumPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters,
+                    "numDiscoveredPrinters");
+
+            if (mNumPrinters > 0) {
+                mListener.onChanged();
+            }
+        }
+    }
+
+    /**
+     * Listener to listen for changes to {@link #getNumPrinters}
+     */
+    public interface OnChangedListener {
+        void onChanged();
+    }
+
+    /**
+     * Exception thrown if the stub has any issues.
+     */
+    public class PluginException extends Exception {
+        private PluginException(PrintServicePlugin plugin, String message, Throwable e) {
+            super(plugin + ": " + message, e);
+        }
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
new file mode 100644
index 0000000..26300b1
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -0,0 +1,199 @@
+/*
+ * 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.printservice.recommendation.plugin.mdnsFilter;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.PrintServicePlugin;
+import com.android.printservice.recommendation.util.MDNSUtils;
+import com.android.printservice.recommendation.util.NsdResolveQueue;
+
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * A plugin listening for mDNS results and only adding the ones that {@link
+ * MDNSUtils#isVendorPrinter match} configured list
+ */
+public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener {
+    private static final String LOG_TAG = "MDNSFilterPlugin";
+
+    private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp";
+
+    /** Name of the print service this plugin is for */
+    private final @StringRes int mName;
+
+    /** Package name of the print service this plugin is for */
+    private final @NonNull CharSequence mPackageName;
+
+    /** mDNS names handled by the print service this plugin is for */
+    private final @NonNull HashSet<String> mMDNSNames;
+
+    /** Printer identifiers of the mPrinters found. */
+    @GuardedBy("mLock")
+    private final @NonNull HashSet<String> mPrinters;
+
+    /** Context of the user of this plugin */
+    private final @NonNull Context mContext;
+
+    /**
+     * Call back to report the number of mPrinters found.
+     *
+     * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
+     * safe to not synchronize access to this field.
+     */
+    private @Nullable PrinterDiscoveryCallback mCallback;
+
+    /** Queue used to resolve nsd infos */
+    private final @NonNull NsdResolveQueue mResolveQueue;
+
+    /**
+     * Create new stub that assumes that a print service can be used to print on all mPrinters
+     * matching some mDNS names.
+     *
+     * @param context     The context the plugin runs in
+     * @param name        The user friendly name of the print service
+     * @param packageName The package name of the print service
+     * @param mDNSNames   The mDNS names of the printer.
+     */
+    public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
+            @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
+        mContext = Preconditions.checkNotNull(context, "context");
+        mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name,
+                "name"), null, mContext.getPackageName());
+        mPackageName = Preconditions.checkStringNotEmpty(packageName);
+        mMDNSNames = new HashSet<>(Preconditions
+                .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames,
+                        "mDNSNames"), "mDNSNames"));
+
+        mResolveQueue = NsdResolveQueue.getInstance();
+        mPrinters = new HashSet<>();
+    }
+
+    @Override
+    public @NonNull CharSequence getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return The NDS manager
+     */
+    private NsdManager getNDSManager() {
+        return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
+    }
+
+    @Override
+    public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
+        mCallback = callback;
+
+        getNDSManager().discoverServices(PRINTER_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
+                this);
+    }
+
+    @Override
+    public @StringRes int getName() {
+        return mName;
+    }
+
+    @Override
+    public void stop() throws Exception {
+        mCallback.onChanged(0);
+        mCallback = null;
+
+        getNDSManager().stopServiceDiscovery(this);
+    }
+
+    @Override
+    public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+        Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
+                + errorCode);
+    }
+
+    @Override
+    public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+        Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
+                + errorCode);
+    }
+
+    @Override
+    public void onDiscoveryStarted(String serviceType) {
+        // empty
+    }
+
+    @Override
+    public void onDiscoveryStopped(String serviceType) {
+        mPrinters.clear();
+    }
+
+    @Override
+    public void onServiceFound(NsdServiceInfo serviceInfo) {
+        mResolveQueue.resolve(getNDSManager(), serviceInfo,
+                new NsdManager.ResolveListener() {
+            @Override
+            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
+                        errorCode);
+            }
+
+            @Override
+            public void onServiceResolved(NsdServiceInfo serviceInfo) {
+                if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
+                    if (mCallback != null) {
+                        boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
+
+                        if (added) {
+                            mCallback.onChanged(mPrinters.size());
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onServiceLost(NsdServiceInfo serviceInfo) {
+        mResolveQueue.resolve(getNDSManager(), serviceInfo,
+                new NsdManager.ResolveListener() {
+            @Override
+            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+                Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
+                        + errorCode);
+            }
+
+            @Override
+            public void onServiceResolved(NsdServiceInfo serviceInfo) {
+                if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
+                    if (mCallback != null) {
+                        boolean removed = mPrinters
+                                .remove(serviceInfo.getHost().getHostAddress());
+
+                        if (removed) {
+                            mCallback.onChanged(mPrinters.size());
+                        }
+                    }
+                }
+            }
+        });
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java
new file mode 100644
index 0000000..57d5c71
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/VendorConfig.java
@@ -0,0 +1,325 @@
+/*
+ * 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.printservice.recommendation.plugin.mdnsFilter;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import com.android.internal.annotations.Immutable;
+import com.android.internal.util.Preconditions;
+import com.android.printservice.recommendation.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Vendor configuration as read from {@link R.xml#vendorconfigs vendorconfigs.xml}. Configuration
+ * can be read via {@link #getConfig(Context, String)}.
+ */
+@Immutable
+public class VendorConfig {
+    /** Lock for {@link #sConfigs} */
+    private static final Object sLock = new Object();
+
+    /** Strings used as XML tags */
+    private static final String VENDORS_TAG = "vendors";
+    private static final String VENDOR_TAG = "vendor";
+    private static final String NAME_TAG = "name";
+    private static final String PACKAGE_TAG = "package";
+    private static final String MDNSNAMES_TAG = "mdns-names";
+    private static final String MDNSNAME_TAG = "mdns-name";
+
+    /** Map from vendor name to config. Initialized on first {@link #getConfig use}. */
+    private static @Nullable ArrayMap<String, VendorConfig> sConfigs;
+
+    /** Localized vendor name */
+    public final @NonNull String name;
+
+    /** Package name containing the print service for this vendor */
+    public final @NonNull String packageName;
+
+    /** mDNS names used by this vendor */
+    public final @NonNull List<String> mDNSNames;
+
+    /**
+     * Create an immutable configuration.
+     */
+    private VendorConfig(@NonNull String name, @NonNull String packageName,
+            @NonNull List<String> mDNSNames) {
+        this.name = Preconditions.checkStringNotEmpty(name);
+        this.packageName = Preconditions.checkStringNotEmpty(packageName);
+        this.mDNSNames = Preconditions.checkCollectionElementsNotNull(mDNSNames, "mDNSName");
+    }
+
+    /**
+     * Get the configuration for a vendor.
+     *
+     * @param context Calling context
+     * @param name    The name of the config to read
+     *
+     * @return the config for the vendor or null if not found
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static @Nullable VendorConfig getConfig(@NonNull Context context, @NonNull String name)
+            throws IOException, XmlPullParserException {
+        synchronized (sLock) {
+            if (sConfigs == null) {
+                sConfigs = readVendorConfigs(context);
+            }
+
+            return sConfigs.get(name);
+        }
+    }
+
+    /**
+     * Get all known vendor configurations.
+     *
+     * @param context Calling context
+     *
+     * @return The known configurations
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static @NonNull Collection<VendorConfig> getAllConfigs(@NonNull Context context)
+            throws IOException, XmlPullParserException {
+        synchronized (sLock) {
+            if (sConfigs == null) {
+                sConfigs = readVendorConfigs(context);
+            }
+
+            return sConfigs.values();
+        }
+    }
+
+    /**
+     * Read the text from a XML tag.
+     *
+     * @param parser XML parser to read from
+     *
+     * @return The text or "" if no text was found
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    private static @NonNull String readText(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        String result = "";
+
+        if (parser.next() == XmlPullParser.TEXT) {
+            result = parser.getText();
+            parser.nextTag();
+        }
+
+        return result;
+    }
+
+    /**
+     * Read a tag with a text content from the parser.
+     *
+     * @param parser  XML parser to read from
+     * @param tagName The name of the tag to read
+     *
+     * @return The text content of the tag
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    private static @NonNull String readSimpleTag(@NonNull Context context,
+            @NonNull XmlPullParser parser, @NonNull String tagName, boolean resolveReferences)
+            throws IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, null, tagName);
+        String text = readText(parser);
+        parser.require(XmlPullParser.END_TAG, null, tagName);
+
+        if (resolveReferences && text.startsWith("@")) {
+            return context.getResources().getString(
+                    context.getResources().getIdentifier(text, null, context.getPackageName()));
+        } else {
+            return text;
+        }
+    }
+
+    /**
+     * Read content of a list of tags.
+     *
+     * @param parser     XML parser to read from
+     * @param tagName    The name of the list tag
+     * @param subTagName The name of the list-element tags
+     * @param tagReader  The {@link TagReader reader} to use to read the tag content
+     * @param <T>        The type of the parsed tag content
+     *
+     * @return A list of {@link T}
+     *
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    private static @NonNull <T> ArrayList<T> readTagList(@NonNull XmlPullParser parser,
+            @NonNull String tagName, @NonNull String subTagName, @NonNull TagReader<T> tagReader)
+            throws XmlPullParserException, IOException {
+        ArrayList<T> entries = new ArrayList<>();
+
+        parser.require(XmlPullParser.START_TAG, null, tagName);
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (parser.getName().equals(subTagName)) {
+                entries.add(tagReader.readTag(parser, subTagName));
+            } else {
+                throw new XmlPullParserException(
+                        "Unexpected subtag of " + tagName + ": " + parser.getName());
+            }
+        }
+
+        return entries;
+    }
+
+    /**
+     * Read the vendor configuration file.
+     *
+     * @param context The content issuing the read
+     *
+     * @return An map pointing from vendor name to config
+     *
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    private static @NonNull ArrayMap<String, VendorConfig> readVendorConfigs(
+            @NonNull final Context context) throws IOException, XmlPullParserException {
+        try (XmlResourceParser parser = context.getResources().getXml(R.xml.vendorconfigs)) {
+            // Skip header
+            int parsingEvent;
+            do {
+                parsingEvent = parser.next();
+            } while (parsingEvent != XmlResourceParser.START_TAG);
+
+            ArrayList<VendorConfig> configs = readTagList(parser, VENDORS_TAG, VENDOR_TAG,
+                    new TagReader<VendorConfig>() {
+                        public VendorConfig readTag(XmlPullParser parser, String tagName)
+                                throws XmlPullParserException, IOException {
+                            return readVendorConfig(context, parser, tagName);
+                        }
+                    });
+
+            ArrayMap<String, VendorConfig> configMap = new ArrayMap<>(configs.size());
+            final int numConfigs = configs.size();
+            for (int i = 0; i < numConfigs; i++) {
+                VendorConfig config = configs.get(i);
+
+                configMap.put(config.name, config);
+            }
+
+            return configMap;
+        }
+    }
+
+    /**
+     * Read a single vendor configuration.
+     *
+     * @param parser  XML parser to read from
+     * @param tagName The vendor tag
+     * @param context Calling context
+     *
+     * @return A config
+     *
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    private static VendorConfig readVendorConfig(@NonNull final Context context,
+            @NonNull XmlPullParser parser, @NonNull String tagName) throws XmlPullParserException,
+            IOException {
+        parser.require(XmlPullParser.START_TAG, null, tagName);
+
+        String name = null;
+        String packageName = null;
+        List<String> mDNSNames = null;
+
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String subTagName = parser.getName();
+
+            switch (subTagName) {
+                case NAME_TAG:
+                    name = readSimpleTag(context, parser, NAME_TAG, false);
+                    break;
+                case PACKAGE_TAG:
+                    packageName = readSimpleTag(context, parser, PACKAGE_TAG, true);
+                    break;
+                case MDNSNAMES_TAG:
+                    mDNSNames = readTagList(parser, MDNSNAMES_TAG, MDNSNAME_TAG,
+                            new TagReader<String>() {
+                                public String readTag(XmlPullParser parser, String tagName)
+                                        throws XmlPullParserException, IOException {
+                                    return readSimpleTag(context, parser, tagName, true);
+                                }
+                            }
+                    );
+                    break;
+                default:
+                    throw new XmlPullParserException("Unexpected subtag of " + tagName + ": "
+                            + subTagName);
+
+            }
+        }
+
+        if (name == null) {
+            throw new XmlPullParserException("name is required");
+        }
+
+        if (packageName == null) {
+            throw new XmlPullParserException("package is required");
+        }
+
+        if (mDNSNames == null) {
+            mDNSNames = Collections.emptyList();
+        }
+
+        // A vendor config should be immutable
+        mDNSNames = Collections.unmodifiableList(mDNSNames);
+
+        return new VendorConfig(name, packageName, mDNSNames);
+    }
+
+    @Override
+    public String toString() {
+        return name + " -> " + packageName + ", " + mDNSNames;
+    }
+
+    /**
+     * Used a a "function pointer" when reading a tag in {@link #readTagList(XmlPullParser, String,
+     * String, TagReader)}.
+     *
+     * @param <T> The type of content to read
+     */
+    private interface TagReader<T> {
+        T readTag(XmlPullParser parser, String tagName) throws XmlPullParserException, IOException;
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
new file mode 100644
index 0000000..0541c35
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/MDNSUtils.java
@@ -0,0 +1,98 @@
+/*
+ * (c) Copyright 2016 Mopria Alliance, Inc.
+ * (c) 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 com.android.printservice.recommendation.util;
+
+import android.annotation.NonNull;
+import android.net.nsd.NsdServiceInfo;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utils for dealing with mDNS attributes
+ */
+public class MDNSUtils {
+    public static final String ATTRIBUTE_TY = "ty";
+    public static final String ATTRIBUTE_PRODUCT = "product";
+    public static final String ATTRIBUTE_USB_MFG = "usb_mfg";
+    public static final String ATTRIBUTE_MFG = "mfg";
+
+    /**
+     * Check if the service has any of a set of vendor names.
+     *
+     * @param serviceInfo The service
+     * @param vendorNames The vendors
+     *
+     * @return true iff the has any of the set of vendor names
+     */
+    public static boolean isVendorPrinter(@NonNull NsdServiceInfo serviceInfo,
+            @NonNull Set<String> vendorNames) {
+        for (Map.Entry<String, byte[]> entry : serviceInfo.getAttributes().entrySet()) {
+            // keys are case insensitive
+            String key = entry.getKey().toLowerCase();
+
+            switch (key) {
+                case ATTRIBUTE_TY:
+                case ATTRIBUTE_PRODUCT:
+                case ATTRIBUTE_USB_MFG:
+                case ATTRIBUTE_MFG:
+                    if (entry.getValue() != null) {
+                        if (containsVendor(new String(entry.getValue(), StandardCharsets.UTF_8),
+                                vendorNames)) {
+                            return true;
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Check if the attribute matches any of the vendor names, ignoring capitalization.
+     *
+     * @param attr        The attribute
+     * @param vendorNames The vendor names
+     *
+     * @return true iff the attribute matches any of the vendor names
+     */
+    private static boolean containsVendor(@NonNull String attr, @NonNull Set<String> vendorNames) {
+        for (String name : vendorNames) {
+            if (containsString(attr.toLowerCase(), name.toLowerCase())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if a string in another string.
+     *
+     * @param container The string that contains the string
+     * @param contained The string that is contained
+     *
+     * @return true if the string is contained in the other
+     */
+    private static boolean containsString(@NonNull String container, @NonNull String contained) {
+        return container.equalsIgnoreCase(contained) || container.contains(contained + " ");
+    }
+}
diff --git a/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java
new file mode 100644
index 0000000..fad50f6
--- /dev/null
+++ b/packages/PrintServiceRecommendationService/src/com/android/printservice/recommendation/util/NsdResolveQueue.java
@@ -0,0 +1,133 @@
+/*
+ * 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.printservice.recommendation.util;
+
+import android.annotation.NonNull;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.LinkedList;
+
+/**
+ * Nsd resolve requests for the same info cancel each other. Hence this class synchronizes the
+ * resolutions to hide this effect.
+ */
+public class NsdResolveQueue {
+    /** Lock for {@link #sInstance} */
+    private static final Object sLock = new Object();
+
+    /** Instance of this singleton */
+    @GuardedBy("sLock")
+    private static NsdResolveQueue sInstance;
+
+    /** Lock for {@link #mResolveRequests} */
+    private final Object mLock = new Object();
+
+    /** Current set of registered service info resolve attempts */
+    @GuardedBy("mLock")
+    private final LinkedList<NsdResolveRequest> mResolveRequests = new LinkedList<>();
+
+    public static NsdResolveQueue getInstance() {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                sInstance = new NsdResolveQueue();
+            }
+
+            return sInstance;
+        }
+    }
+
+    /**
+     * Container for a request to resolve a serviceInfo.
+     */
+    private static class NsdResolveRequest {
+        final @NonNull NsdManager nsdManager;
+        final @NonNull NsdServiceInfo serviceInfo;
+        final @NonNull NsdManager.ResolveListener listener;
+
+        private NsdResolveRequest(@NonNull NsdManager nsdManager,
+                @NonNull NsdServiceInfo serviceInfo, @NonNull NsdManager.ResolveListener listener) {
+            this.nsdManager = nsdManager;
+            this.serviceInfo = serviceInfo;
+            this.listener = listener;
+        }
+    }
+
+    /**
+     * Resolve a serviceInfo or queue the request if there is a request currently in flight.
+     *
+     * @param nsdManager  The nsd manager to use
+     * @param serviceInfo The service info to resolve
+     * @param listener    The listener to call back once the info is resolved.
+     */
+    public void resolve(@NonNull NsdManager nsdManager, @NonNull NsdServiceInfo serviceInfo,
+            @NonNull NsdManager.ResolveListener listener) {
+        synchronized (mLock) {
+            mResolveRequests.addLast(new NsdResolveRequest(nsdManager, serviceInfo,
+                    new ListenerWrapper(listener)));
+
+            if (mResolveRequests.size() == 1) {
+                resolveNextRequest();
+            }
+        }
+    }
+
+    /**
+     * Wrapper for a {@link NsdManager.ResolveListener}. Calls the listener and then
+     * {@link #resolveNextRequest()}.
+     */
+    private class ListenerWrapper implements NsdManager.ResolveListener {
+        private final @NonNull NsdManager.ResolveListener mListener;
+
+        private ListenerWrapper(@NonNull NsdManager.ResolveListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+            mListener.onResolveFailed(serviceInfo, errorCode);
+
+            synchronized (mLock) {
+                mResolveRequests.pop();
+                resolveNextRequest();
+            }
+        }
+
+        @Override
+        public void onServiceResolved(NsdServiceInfo serviceInfo) {
+            mListener.onServiceResolved(serviceInfo);
+
+            synchronized (mLock) {
+                mResolveRequests.pop();
+                resolveNextRequest();
+            }
+        }
+    }
+
+    /**
+     * Resolve the next request if there is one.
+     */
+    private void resolveNextRequest() {
+        if (!mResolveRequests.isEmpty()) {
+            NsdResolveRequest request = mResolveRequests.getFirst();
+
+            request.nsdManager.resolveService(request.serviceInfo, request.listener);
+        }
+    }
+
+}
diff --git a/packages/PrintSpooler/res/drawable/ic_download_from_market.xml b/packages/PrintSpooler/res/drawable/ic_download_from_market.xml
new file mode 100644
index 0000000..44a5edf
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_download_from_market.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="36dp"
+        android:height="36dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+            android:pathData="M40,12h-8L32,8l-4,-4h-8l-4,4v4L8,12c-2.21,0 -3.98,1.79 -3.98,4L4,38c0,2.21 1.79,4 4,4h32c2.21,0 4,-1.79 4,-4L44,16c0,-2.21 -1.79,-4 -4,-4zM20,8h8v4h-8L20,8zM24,38L14,28h6v-8h8v8h6L24,38z"
+            android:fillColor="?android:attr/colorAccent"/>
+</vector>
diff --git a/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml b/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml
new file mode 100644
index 0000000..86ac26d
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_service_recommendations_list_item.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <ImageView
+        android:layout_width="36dip"
+        android:layout_height="36dip"
+        android:src="@drawable/ic_download_from_market"
+        android:layout_marginRight="4dip"
+        android:layout_gravity="center_vertical"
+        android:contentDescription="@null" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dip">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:singleLine="true"
+            android:ellipsize="end" />
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:text="@string/enable_print_service" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index 2bc5ab6..c647dab 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -99,6 +99,6 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"Кешіріңіз, бұл нәтиже бермеді. Әрекетті қайталаңыз."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Қайталау"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Бұл принтер дәл қазір қол жетімді емес."</string>
-    <string name="print_cannot_load_page" msgid="6179560924492912009">"Алдын ала қарауды көрсету мүмкін емес"</string>
+    <string name="print_cannot_load_page" msgid="6179560924492912009">"Бетті алдын ала қарау мүмкін емес"</string>
     <string name="print_preparing_preview" msgid="3939930735671364712">"Алдын ала қарау дайындалуда…"</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 2f24d2c..2836adb 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -185,6 +185,12 @@
     <!-- Label for the list item that links to the list of all print services. [CHAR LIMIT=50] -->
     <string name="all_services_title">All services</string>
 
+    <!-- Subtitle for a print service recommendation. [CHAR LIMIT=50] -->
+    <plurals name="print_services_recommendation_subtitle">
+        <item quantity="one">Install to discover <xliff:g id="count" example="1">%1$s</xliff:g> printer</item>
+        <item quantity="other">Install to discover <xliff:g id="count" example="2">%1$s</xliff:g> printers</item>
+    </plurals>
+
     <!-- Notifications -->
 
     <!-- Template for the notification label for a printing print job. [CHAR LIMIT=25] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index af4c347..0feda92 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -244,9 +244,20 @@
 
                 ranges = PageRangeUtils.normalize(ranges);
 
+                int lastPageIdx = mEditor.getPageCount() - 1;
+
                 final int rangeCount = ranges.length;
                 for (int i = rangeCount - 1; i >= 0; i--) {
                     PageRange range = ranges[i];
+
+                    // Ignore removal of pages that are outside the document
+                    if (range.getEnd() > lastPageIdx) {
+                        if (range.getStart() > lastPageIdx) {
+                            continue;
+                        }
+                        range = new PageRange(range.getStart(), lastPageIdx);
+                    }
+
                     for (int j = range.getEnd(); j >= range.getStart(); j--) {
                         mEditor.removePage(j);
                     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index f2b3e6e..42ef10e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -30,10 +30,13 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
+import android.print.PrintServiceRecommendationsLoader;
 import android.print.PrintServicesLoader;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
@@ -45,8 +48,10 @@
 import android.widget.TextView;
 import com.android.printspooler.R;
 
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -57,31 +62,38 @@
  *         when the item is clicked.</li>
  *     <li>{@link #mDisabledServicesAdapter} for all disabled services. Once clicked the settings page
  *         for this service is opened.</li>
- *     <li>{@link RecommendedServicesAdapter} for a link to all services. If this item is clicked
+ *     <li>{@link #mRecommendedServicesAdapter} for a link to all services. If this item is clicked
  *         the market app is opened to show all print services.</li>
  * </ul>
  */
-public class AddPrinterActivity extends ListActivity implements
-        LoaderManager.LoaderCallbacks<List<PrintServiceInfo>>,
-        AdapterView.OnItemClickListener {
+public class AddPrinterActivity extends ListActivity implements AdapterView.OnItemClickListener {
     private static final String LOG_TAG = "AddPrinterActivity";
 
     /** Ids for the loaders */
     private static final int LOADER_ID_ENABLED_SERVICES = 1;
     private static final int LOADER_ID_DISABLED_SERVICES = 2;
+    private static final int LOADER_ID_RECOMMENDED_SERVICES = 3;
+    private static final int LOADER_ID_ALL_SERVICES = 4;
 
     /**
      * The enabled services list. This is filled from the {@link #LOADER_ID_ENABLED_SERVICES}
-     * loader in {@link #onLoadFinished}.
+     * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
      */
     private EnabledServicesAdapter mEnabledServicesAdapter;
 
     /**
      * The disabled services list. This is filled from the {@link #LOADER_ID_DISABLED_SERVICES}
-     * loader in {@link #onLoadFinished}.
+     * loader in {@link PrintServiceInfoLoaderCallbacks#onLoadFinished}.
      */
     private DisabledServicesAdapter mDisabledServicesAdapter;
 
+    /**
+     * The recommended services list. This is filled from the
+     * {@link #LOADER_ID_RECOMMENDED_SERVICES} loader in
+     * {@link PrintServicePrintServiceRecommendationLoaderCallbacks#onLoadFinished}.
+     */
+    private RecommendedServicesAdapter mRecommendedServicesAdapter;
+
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -90,36 +102,116 @@
 
         mEnabledServicesAdapter = new EnabledServicesAdapter();
         mDisabledServicesAdapter = new DisabledServicesAdapter();
+        mRecommendedServicesAdapter = new RecommendedServicesAdapter();
 
         ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
         adapterList.add(mEnabledServicesAdapter);
-        adapterList.add(new RecommendedServicesAdapter());
+        adapterList.add(mRecommendedServicesAdapter);
         adapterList.add(mDisabledServicesAdapter);
 
         setListAdapter(new CombinedAdapter(adapterList));
 
         getListView().setOnItemClickListener(this);
 
-        getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, this);
-        getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, this);
-        // TODO: Load recommended services
+        PrintServiceInfoLoaderCallbacks printServiceLoaderCallbacks =
+                new PrintServiceInfoLoaderCallbacks();
+
+        getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
+        getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
+        getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
+                new PrintServicePrintServiceRecommendationLoaderCallbacks());
+        getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
     }
 
-    @Override
-    public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
-        switch (id) {
-            case LOADER_ID_ENABLED_SERVICES:
-                return new PrintServicesLoader(
-                        (PrintManager) getSystemService(Context.PRINT_SERVICE), this,
-                        PrintManager.ENABLED_SERVICES);
-            case LOADER_ID_DISABLED_SERVICES:
-                return new PrintServicesLoader(
-                        (PrintManager) getSystemService(Context.PRINT_SERVICE), this,
-                        PrintManager.DISABLED_SERVICES);
-            // TODO: Load recommended services
-            default:
-                // not reached
-                return null;
+    /**
+     * Callbacks for the loaders operating on list of {@link PrintServiceInfo print service infos}.
+     */
+    private class PrintServiceInfoLoaderCallbacks implements
+            LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
+        @Override
+        public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
+            switch (id) {
+                case LOADER_ID_ENABLED_SERVICES:
+                    return new PrintServicesLoader(
+                            (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                            AddPrinterActivity.this, PrintManager.ENABLED_SERVICES);
+                case LOADER_ID_DISABLED_SERVICES:
+                    return new PrintServicesLoader(
+                            (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                            AddPrinterActivity.this, PrintManager.DISABLED_SERVICES);
+                case LOADER_ID_ALL_SERVICES:
+                    return new PrintServicesLoader(
+                            (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                            AddPrinterActivity.this, PrintManager.ALL_SERVICES);
+                default:
+                    // not reached
+                    return null;
+            }
+        }
+
+
+        @Override
+        public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
+                List<PrintServiceInfo> data) {
+            switch (loader.getId()) {
+                case LOADER_ID_ENABLED_SERVICES:
+                    mEnabledServicesAdapter.updateData(data);
+                    break;
+                case LOADER_ID_DISABLED_SERVICES:
+                    mDisabledServicesAdapter.updateData(data);
+                    break;
+                case LOADER_ID_ALL_SERVICES:
+                    mRecommendedServicesAdapter.updateInstalledServices(data);
+                default:
+                    // not reached
+            }
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
+            if (!isFinishing()) {
+                switch (loader.getId()) {
+                    case LOADER_ID_ENABLED_SERVICES:
+                        mEnabledServicesAdapter.updateData(null);
+                        break;
+                    case LOADER_ID_DISABLED_SERVICES:
+                        mDisabledServicesAdapter.updateData(null);
+                        break;
+                    case LOADER_ID_ALL_SERVICES:
+                        mRecommendedServicesAdapter.updateInstalledServices(null);
+                        break;
+                    default:
+                        // not reached
+                }
+            }
+        }
+    }
+
+    /**
+     * Callbacks for the loaders operating on list of {@link RecommendationInfo print service
+     * recommendations}.
+     */
+    private class PrintServicePrintServiceRecommendationLoaderCallbacks implements
+            LoaderManager.LoaderCallbacks<List<RecommendationInfo>> {
+        @Override
+        public Loader<List<RecommendationInfo>> onCreateLoader(int id, Bundle args) {
+            return new PrintServiceRecommendationsLoader(
+                    (PrintManager) getSystemService(Context.PRINT_SERVICE),
+                    AddPrinterActivity.this);
+        }
+
+
+        @Override
+        public void onLoadFinished(Loader<List<RecommendationInfo>> loader,
+                List<RecommendationInfo> data) {
+            mRecommendedServicesAdapter.updateRecommendations(data);
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<RecommendationInfo>> loader) {
+            if (!isFinishing()) {
+                mRecommendedServicesAdapter.updateRecommendations(null);
+            }
         }
     }
 
@@ -128,39 +220,6 @@
         ((ActionAdapter) getListAdapter()).performAction(position);
     }
 
-    @Override
-    public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
-            List<PrintServiceInfo> data) {
-        switch (loader.getId()) {
-            case LOADER_ID_ENABLED_SERVICES:
-                mEnabledServicesAdapter.updateData(data);
-                break;
-            case LOADER_ID_DISABLED_SERVICES:
-                mDisabledServicesAdapter.updateData(data);
-                break;
-            // TODO: Load recommended services
-            default:
-                // not reached
-        }
-    }
-
-    @Override
-    public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
-        if (!isFinishing()) {
-            switch (loader.getId()) {
-                case LOADER_ID_ENABLED_SERVICES:
-                    mEnabledServicesAdapter.updateData(null);
-                    break;
-                case LOADER_ID_DISABLED_SERVICES:
-                    mDisabledServicesAdapter.updateData(null);
-                    break;
-                // TODO: Reset recommended services
-                default:
-                    // not reached
-            }
-        }
-    }
-
     /**
      * Marks an adapter that can can perform an action for a position in it's list.
      */
@@ -490,28 +549,65 @@
      * Adapter for the recommended services.
      */
     private class RecommendedServicesAdapter extends ActionAdapter {
+        /** Package names of all installed print services */
+        private @NonNull final ArraySet<String> mInstalledServices;
+
+        /** All print service recommendations */
+        private @Nullable List<RecommendationInfo> mRecommendations;
+
+        /**
+         * Sorted print service recommendations for services that are not installed
+         *
+         * @see #filterRecommendations
+         */
+        private @Nullable List<RecommendationInfo> mFilteredRecommendations;
+
+        /**
+         * Create a new adapter.
+         */
+        private RecommendedServicesAdapter() {
+            mInstalledServices = new ArraySet<>();
+        }
+
         @Override
         public int getCount() {
-            return 2;
+            if (mFilteredRecommendations == null) {
+                return 2;
+            } else {
+                return mFilteredRecommendations.size() + 2;
+            }
         }
 
         @Override
         public int getViewTypeCount() {
-            return 2;
+            return 3;
+        }
+
+        /**
+         * @return The position the all services link is at.
+         */
+        private int getAllServicesPos() {
+            return getCount() - 1;
         }
 
         @Override
         public int getItemViewType(int position) {
             if (position == 0) {
                 return 0;
-            } else {
+            } else if (getAllServicesPos() == position) {
                 return 1;
+            } else {
+                return 2;
             }
         }
 
         @Override
         public Object getItem(int position) {
-            return null;
+            if (position == 0 || position == getAllServicesPos()) {
+                return null;
+            } else {
+                return mFilteredRecommendations.get(position - 1);
+            }
         }
 
         @Override
@@ -531,11 +627,27 @@
                         .setText(R.string.recommended_services_title);
 
                 return convertView;
-            }
+            } else if (position == getAllServicesPos()) {
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
+                            parent, false);
+                }
+            } else {
+                RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
 
-            if (convertView == null) {
-                convertView = getLayoutInflater().inflate(R.layout.all_print_services_list_item,
-                        parent, false);
+                if (convertView == null) {
+                    convertView = getLayoutInflater().inflate(
+                            R.layout.print_service_recommendations_list_item, parent, false);
+                }
+
+                ((TextView) convertView.findViewById(R.id.title)).setText(recommendation.getName());
+
+                ((TextView) convertView.findViewById(R.id.subtitle)).setText(getResources()
+                        .getQuantityString(R.plurals.print_services_recommendation_subtitle,
+                                recommendation.getNumDiscoveredPrinters(),
+                                recommendation.getNumDiscoveredPrinters()));
+
+                return convertView;
             }
 
             return convertView;
@@ -548,16 +660,107 @@
 
         @Override
         public void performAction(@IntRange(from = 0) int position) {
-            String searchUri = Settings.Secure
-                    .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
+            if (position == getAllServicesPos()) {
+                String searchUri = Settings.Secure
+                        .getString(getContentResolver(), Settings.Secure.PRINT_SERVICE_SEARCH_URI);
 
-            if (searchUri != null) {
+                if (searchUri != null) {
+                    try {
+                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
+                    } catch (ActivityNotFoundException e) {
+                        Log.e(LOG_TAG, "Cannot start market", e);
+                    }
+                }
+            } else {
+                RecommendationInfo recommendation = (RecommendationInfo) getItem(position);
+
                 try {
-                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
+                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(
+                            R.string.uri_package_details, recommendation.getPackageName()))));
                 } catch (ActivityNotFoundException e) {
                     Log.e(LOG_TAG, "Cannot start market", e);
                 }
             }
         }
+
+        /**
+         * Filter recommended services.
+         */
+        private void filterRecommendations() {
+            if (mRecommendations == null) {
+                mFilteredRecommendations = null;
+            } else {
+                mFilteredRecommendations = new ArrayList<>();
+
+                // Filter out recommendations for already installed services
+                final int numRecommendations = mRecommendations.size();
+                for (int i = 0; i < numRecommendations; i++) {
+                    RecommendationInfo recommendation = mRecommendations.get(i);
+
+                    if (!mInstalledServices.contains(recommendation.getPackageName())) {
+                        mFilteredRecommendations.add(recommendation);
+                    }
+                }
+            }
+
+            notifyDataSetChanged();
+        }
+
+        /**
+         * Update the installed print services.
+         *
+         * @param services The new set of services
+         */
+        public void updateInstalledServices(List<PrintServiceInfo> services) {
+            mInstalledServices.clear();
+
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                mInstalledServices.add(services.get(i).getComponentName().getPackageName());
+            }
+
+            filterRecommendations();
+        }
+
+        /**
+         * Update the recommended print services.
+         *
+         * @param recommendations The new set of recommendations
+         */
+        public void updateRecommendations(List<RecommendationInfo> recommendations) {
+            if (recommendations != null) {
+                final Collator collator = Collator.getInstance();
+
+                // Sort recommendations (early conditions are more important)
+                // - higher number of discovered printers first
+                // - single vendor services first
+                // - alphabetically
+                Collections.sort(recommendations,
+                        new Comparator<RecommendationInfo>() {
+                            @Override public int compare(RecommendationInfo o1,
+                                    RecommendationInfo o2) {
+                                if (o1.getNumDiscoveredPrinters() !=
+                                        o2.getNumDiscoveredPrinters()) {
+                                    return o2.getNumDiscoveredPrinters() -
+                                            o1.getNumDiscoveredPrinters();
+                                } else if (o1.recommendsMultiVendorService()
+                                        != o2.recommendsMultiVendorService()) {
+                                    if (o1.recommendsMultiVendorService()) {
+                                        return 1;
+                                    } else {
+                                        return -1;
+                                    }
+                                } else {
+                                    return collator.compare(o1.getName().toString(),
+                                            o2.getName().toString());
+                                }
+                            }
+                        });
+            }
+
+            mRecommendations = recommendations;
+
+            filterRecommendations();
+        }
     }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index eebb60c..c1a3f86 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -206,6 +206,7 @@
             int documentPageCount, MediaSize mediaSize, Margins minMargins) {
         boolean documentChanged = false;
         boolean updatePreviewAreaAndPageSize = false;
+        boolean clearSelectedPages = false;
 
         // If the app does not tell how many pages are in the document we cannot
         // optimize and ask for all pages whose count we get from the renderer.
@@ -225,30 +226,41 @@
             }
         }
 
-        if (!Arrays.equals(mSelectedPages, selectedPages)) {
-            mSelectedPages = selectedPages;
-            mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
-                    mSelectedPages, documentPageCount);
-            setConfirmedPages(mSelectedPages, documentPageCount);
-            updatePreviewAreaAndPageSize = true;
-            documentChanged = true;
-        }
-
         if (mDocumentPageCount != documentPageCount) {
             mDocumentPageCount = documentPageCount;
             documentChanged = true;
+            clearSelectedPages = true;
         }
 
         if (mMediaSize == null || !mMediaSize.equals(mediaSize)) {
             mMediaSize = mediaSize;
             updatePreviewAreaAndPageSize = true;
             documentChanged = true;
+
+            clearSelectedPages = true;
         }
 
         if (mMinMargins == null || !mMinMargins.equals(minMargins)) {
             mMinMargins = minMargins;
             updatePreviewAreaAndPageSize = true;
             documentChanged = true;
+
+            clearSelectedPages = true;
+        }
+
+        if (clearSelectedPages) {
+            mSelectedPages = PageRange.ALL_PAGES_ARRAY;
+            mSelectedPageCount = documentPageCount;
+            setConfirmedPages(mSelectedPages, documentPageCount);
+            updatePreviewAreaAndPageSize = true;
+            documentChanged = true;
+        } else if (!Arrays.equals(mSelectedPages, selectedPages)) {
+            mSelectedPages = selectedPages;
+            mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
+                    mSelectedPages, documentPageCount);
+            setConfirmedPages(mSelectedPages, documentPageCount);
+            updatePreviewAreaAndPageSize = true;
+            documentChanged = true;
         }
 
         // If *all pages* is selected we need to convert that to absolute
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index a24d664..cde0fa3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -128,8 +128,6 @@
 
     private static final boolean DEBUG = false;
 
-    public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
-
     private static final String FRAGMENT_TAG = "FRAGMENT_TAG";
 
     private static final String HAS_PRINTED_PREF = "has_printed";
@@ -176,8 +174,6 @@
             "[\\s]*[0-9]+[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
                     + "[\\s]*[0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
 
-    public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[]{PageRange.ALL_PAGES};
-
     private boolean mIsOptionsUiBound = false;
 
     private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
@@ -480,7 +476,7 @@
     }
 
     private void onPrintDocumentError(String message) {
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY);
 
         setState(STATE_UPDATE_FAILED);
@@ -506,7 +502,7 @@
             Log.i(LOG_TAG, "onUpdateCanceled()");
         }
 
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensurePreviewUiShown();
 
         switch (mState) {
@@ -528,7 +524,7 @@
             Log.i(LOG_TAG, "onUpdateCompleted()");
         }
 
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensurePreviewUiShown();
 
         // Update the print job with the info for the written document. The page
@@ -576,7 +572,7 @@
             Log.i(LOG_TAG, "onUpdateFailed()");
         }
 
-        mProgressMessageController.cancel();
+        setState(mProgressMessageController.cancel());
         ensureErrorUiShown(error, PrintErrorFragment.ACTION_RETRY);
 
         if (mState == STATE_CREATE_FILE_FAILED
@@ -597,14 +593,6 @@
 
     @Override
     public void onOptionsClosed() {
-        PageRange[] selectedPages = computeSelectedPages();
-        if (!Arrays.equals(mSelectedPages, selectedPages)) {
-            mSelectedPages = selectedPages;
-
-            // Update preview.
-            updatePrintPreviewController(false);
-        }
-
         // Make sure the IME is not on the way of preview as
         // the user may have used it to type copies or range.
         InputMethodManager imm = getSystemService(InputMethodManager.class);
@@ -717,21 +705,17 @@
 
     private void onSelectPrinterActivityResult(int resultCode, Intent data) {
         if (resultCode == RESULT_OK && data != null) {
-            PrinterId printerId = data.getParcelableExtra(INTENT_EXTRA_PRINTER_ID);
-            if (printerId != null) {
-                mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerId);
-                final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
-                if (index != AdapterView.INVALID_POSITION) {
-                    mDestinationSpinner.setSelection(index);
-                    return;
-                }
+            PrinterInfo printerInfo = data.getParcelableExtra(
+                    SelectPrinterActivity.INTENT_EXTRA_PRINTER);
+            if (printerInfo != null) {
+                mCurrentPrinter = printerInfo;
+                mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerInfo);
             }
         }
 
         if (mCurrentPrinter != null) {
-            PrinterId printerId = mCurrentPrinter.getId();
-            final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
-            mDestinationSpinner.setSelection(index);
+            // Trigger PrintersObserver.onChanged() to adjust selection back to current printer
+            mDestinationSpinnerAdapter.notifyDataSetChanged();
         }
     }
 
@@ -950,7 +934,7 @@
         mSelectedPages = selectedPages;
         mPrintJob.setPages(selectedPages);
 
-        if (Arrays.equals(selectedPages, ALL_PAGES_ARRAY)) {
+        if (Arrays.equals(selectedPages, PageRange.ALL_PAGES_ARRAY)) {
             if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
                 mRangeOptionsSpinner.setSelection(0);
                 mPageRangeEditText.setText("");
@@ -1049,7 +1033,22 @@
         }
     }
 
+    /**
+     * Clear the selected page range and update the preview if needed.
+     */
+    private void clearPageRanges() {
+        mRangeOptionsSpinner.setSelection(0);
+        mPageRangeEditText.setError(null);
+        mPageRangeEditText.setText("");
+        mSelectedPages = PageRange.ALL_PAGES_ARRAY;
+
+        if (!Arrays.equals(mSelectedPages, mPrintPreviewController.getSelectedPages())) {
+            updatePrintPreviewController(false);
+        }
+    }
+
     private void updatePrintAttributesFromCapabilities(PrinterCapabilitiesInfo capabilities) {
+        boolean clearRanges = false;
         PrintAttributes defaults = capabilities.getDefaults();
 
         // Sort the media sizes based on the current locale.
@@ -1061,6 +1060,7 @@
         // Media size.
         MediaSize currMediaSize = attributes.getMediaSize();
         if (currMediaSize == null) {
+            clearRanges = true;
             attributes.setMediaSize(defaults.getMediaSize());
         } else {
             MediaSize newMediaSize = null;
@@ -1079,6 +1079,7 @@
             }
             // If we did not find the current media size fall back to default.
             if (newMediaSize == null) {
+                clearRanges = true;
                 newMediaSize = defaults.getMediaSize();
             }
 
@@ -1110,7 +1111,14 @@
         }
 
         // Margins.
+        if (!Objects.equals(attributes.getMinMargins(), defaults.getMinMargins())) {
+            clearRanges = true;
+        }
         attributes.setMinMargins(defaults.getMinMargins());
+
+        if (clearRanges) {
+            clearPageRanges();
+        }
     }
 
     private boolean updateDocument(boolean clearLastError) {
@@ -1161,6 +1169,18 @@
         doFinish();
     }
 
+    /**
+     * Update the selected pages from the text field.
+     */
+    private void updateSelectedPagesFromTextField() {
+        PageRange[] selectedPages = computeSelectedPages();
+        if (!Arrays.equals(mSelectedPages, selectedPages)) {
+            mSelectedPages = selectedPages;
+            // Update preview.
+            updatePrintPreviewController(false);
+        }
+    }
+
     private void confirmPrint() {
         setState(STATE_PRINT_CONFIRMED);
 
@@ -1170,14 +1190,10 @@
         addCurrentPrinterToHistory();
         setUserPrinted();
 
-        PageRange[] selectedPages = computeSelectedPages();
-        if (!Arrays.equals(mSelectedPages, selectedPages)) {
-            mSelectedPages = selectedPages;
-            // Update preview.
-            updatePrintPreviewController(false);
-        }
-
+        // updateSelectedPagesFromTextField migth update the preview, hence apply the preview first
         updateSelectedPagesFromPreview();
+        updateSelectedPagesFromTextField();
+
         mPrintPreviewController.closeOptions();
 
         if (canUpdateDocument()) {
@@ -1262,6 +1278,7 @@
         // Page range
         mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
         mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
+        mPageRangeEditText.setVisibility(View.INVISIBLE);
         mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
         mPageRangeEditText.addTextChangedListener(new RangeTextWatcher());
 
@@ -1476,6 +1493,10 @@
                     cancelPrint();
                 }
             } else if (view == mMoreOptionsButton) {
+                // The selected pages is only applied once the user leaves the text field. A click
+                // on this button, does not count as leaving.
+                updateSelectedPagesFromTextField();
+
                 if (mCurrentPrinter != null) {
                     startAdvancedPrintOptionsActivity(mCurrentPrinter);
                 }
@@ -1753,36 +1774,38 @@
         // Range options
         PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
         final int pageCount = getAdjustedPageCount(info);
-        if (info != null && pageCount > 0) {
-            if (pageCount == 1) {
-                mRangeOptionsSpinner.setEnabled(false);
-            } else {
-                mRangeOptionsSpinner.setEnabled(true);
-                if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
-                    if (!mPageRangeEditText.isEnabled()) {
-                        mPageRangeEditText.setEnabled(true);
-                        mPageRangeEditText.setVisibility(View.VISIBLE);
-                        mPageRangeTitle.setVisibility(View.VISIBLE);
-                        mPageRangeEditText.requestFocus();
-                        InputMethodManager imm = (InputMethodManager)
-                                getSystemService(Context.INPUT_METHOD_SERVICE);
-                        imm.showSoftInput(mPageRangeEditText, 0);
-                    }
+        if (pageCount > 0) {
+            if (info != null) {
+                if (pageCount == 1) {
+                    mRangeOptionsSpinner.setEnabled(false);
                 } else {
-                    mPageRangeEditText.setEnabled(false);
-                    mPageRangeEditText.setVisibility(View.INVISIBLE);
-                    mPageRangeTitle.setVisibility(View.INVISIBLE);
+                    mRangeOptionsSpinner.setEnabled(true);
+                    if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
+                        if (!mPageRangeEditText.isEnabled()) {
+                            mPageRangeEditText.setEnabled(true);
+                            mPageRangeEditText.setVisibility(View.VISIBLE);
+                            mPageRangeTitle.setVisibility(View.VISIBLE);
+                            mPageRangeEditText.requestFocus();
+                            InputMethodManager imm = (InputMethodManager)
+                                    getSystemService(Context.INPUT_METHOD_SERVICE);
+                            imm.showSoftInput(mPageRangeEditText, 0);
+                        }
+                    } else {
+                        mPageRangeEditText.setEnabled(false);
+                        mPageRangeEditText.setVisibility(View.INVISIBLE);
+                        mPageRangeTitle.setVisibility(View.INVISIBLE);
+                    }
                 }
+            } else {
+                if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+                    mRangeOptionsSpinner.setSelection(0);
+                    mPageRangeEditText.setText("");
+                }
+                mRangeOptionsSpinner.setEnabled(false);
+                mPageRangeEditText.setEnabled(false);
+                mPageRangeEditText.setVisibility(View.INVISIBLE);
+                mPageRangeTitle.setVisibility(View.INVISIBLE);
             }
-        } else {
-            if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
-                mRangeOptionsSpinner.setSelection(0);
-                mPageRangeEditText.setText("");
-            }
-            mRangeOptionsSpinner.setEnabled(false);
-            mPageRangeEditText.setEnabled(false);
-            mPageRangeEditText.setVisibility(View.INVISIBLE);
-            mPageRangeTitle.setVisibility(View.INVISIBLE);
         }
 
         final int newPageCount = getAdjustedPageCount(info);
@@ -1933,7 +1956,7 @@
             return PageRangeUtils.normalize(pageRangesArray);
         }
 
-        return ALL_PAGES_ARRAY;
+        return PageRange.ALL_PAGES_ARRAY;
     }
 
     private int getAdjustedPageCount(PrintDocumentInfo info) {
@@ -2055,8 +2078,9 @@
             mSpoolerProvider.destroy();
         }
 
+        setState(mProgressMessageController.cancel());
+
         if (mState != STATE_INITIALIZING) {
-            mProgressMessageController.cancel();
             mPrintedDocument.finish();
             mPrintedDocument.destroy();
             mPrintPreviewController.destroy(new Runnable() {
@@ -2229,23 +2253,36 @@
             return AdapterView.INVALID_POSITION;
         }
 
-        public void ensurePrinterInVisibleAdapterPosition(PrinterId printerId) {
+        public void ensurePrinterInVisibleAdapterPosition(PrinterInfo printer) {
             final int printerCount = mPrinterHolders.size();
+            boolean isKnownPrinter = false;
             for (int i = 0; i < printerCount; i++) {
                 PrinterHolder printerHolder = mPrinterHolders.get(i);
-                if (printerHolder.printer.getId().equals(printerId)) {
+
+                if (printerHolder.printer.getId().equals(printer.getId())) {
+                    isKnownPrinter = true;
+
                     // If already in the list - do nothing.
                     if (i < getCount() - 2) {
-                        return;
+                        break;
                     }
                     // Else replace the last one (two items are not printers).
                     final int lastPrinterIndex = getCount() - 3;
                     mPrinterHolders.set(i, mPrinterHolders.get(lastPrinterIndex));
                     mPrinterHolders.set(lastPrinterIndex, printerHolder);
-                    notifyDataSetChanged();
-                    return;
+                    break;
                 }
             }
+
+            if (!isKnownPrinter) {
+                PrinterHolder printerHolder = new PrinterHolder(printer);
+                printerHolder.removed = true;
+
+                mPrinterHolders.add(Math.max(0, getCount() - 3), printerHolder);
+            }
+
+            // Force reload to adjust selection in PrintersObserver.onChanged()
+            notifyDataSetChanged();
         }
 
         @Override
@@ -2428,8 +2465,7 @@
             List<PrinterHolder> newPrinterHolders = new ArrayList<>();
 
             // Update printers we already have which are either updated or removed.
-            // We do not remove printers if the currently selected printer is removed
-            // to prevent the user printing to a wrong printer.
+            // We do not remove the currently selected printer.
             final int oldPrinterCount = mPrinterHolders.size();
             for (int i = 0; i < oldPrinterCount; i++) {
                 PrinterHolder printerHolder = mPrinterHolders.get(i);
@@ -2438,10 +2474,11 @@
                 if (updatedPrinter != null) {
                     printerHolder.printer = updatedPrinter;
                     printerHolder.removed = false;
-                } else {
+                    newPrinterHolders.add(printerHolder);
+                } else if (mCurrentPrinter != null && mCurrentPrinter.getId().equals(oldPrinterId)){
                     printerHolder.removed = true;
+                    newPrinterHolders.add(printerHolder);
                 }
-                newPrinterHolders.add(printerHolder);
             }
 
             // Add the rest of the new printers, i.e. what is left.
@@ -2473,14 +2510,25 @@
             return null;
         }
 
-        public void pruneRemovedPrinters() {
+        /**
+         * Remove a printer from the holders if it is marked as removed.
+         *
+         * @param printerId the id of the printer to remove.
+         *
+         * @return true iff the printer was removed.
+         */
+        public boolean pruneRemovedPrinter(PrinterId printerId) {
             final int holderCounts = mPrinterHolders.size();
             for (int i = holderCounts - 1; i >= 0; i--) {
                 PrinterHolder printerHolder = mPrinterHolders.get(i);
-                if (printerHolder.removed) {
+
+                if (printerHolder.printer.getId().equals(printerId) && printerHolder.removed) {
                     mPrinterHolders.remove(i);
+                    return true;
                 }
             }
+
+            return false;
         }
 
         private void addPrinters(List<PrinterHolder> list, Collection<PrinterInfo> printers) {
@@ -2525,17 +2573,17 @@
 
             PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
                     oldPrinterState.getId());
-            if (printerHolder == null) {
-                return;
-            }
             PrinterInfo newPrinterState = printerHolder.printer;
 
-            if (!printerHolder.removed) {
-                mDestinationSpinnerAdapter.pruneRemovedPrinters();
-            } else {
+            if (printerHolder.removed) {
                 onPrinterUnavailable(newPrinterState);
             }
 
+            if (mDestinationSpinner.getSelectedItem() != printerHolder) {
+                mDestinationSpinner.setSelection(
+                        mDestinationSpinnerAdapter.getPrinterIndex(newPrinterState.getId()));
+            }
+
             if (oldPrinterState.equals(newPrinterState)) {
                 return;
             }
@@ -2607,6 +2655,8 @@
     private final class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
         @Override
         public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
+            boolean clearRanges = false;
+
             if (spinner == mDestinationSpinner) {
                 if (position == AdapterView.INVALID_POSITION) {
                     return;
@@ -2625,13 +2675,28 @@
                     return;
                 }
 
+                PrinterId oldId = null;
+                if (mCurrentPrinter != null) {
+                    oldId = mCurrentPrinter.getId();
+                }
+
                 mCurrentPrinter = currentPrinter;
 
+                if (oldId != null) {
+                    boolean printerRemoved = mDestinationSpinnerAdapter.pruneRemovedPrinter(oldId);
+
+                    if (printerRemoved) {
+                        // Trigger PrinterObserver.onChanged to adjust selection. This will call
+                        // this function again.
+                        mDestinationSpinnerAdapter.notifyDataSetChanged();
+                        return;
+                    }
+                }
+
                 PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
                         currentPrinter.getId());
                 if (!printerHolder.removed) {
                     setState(STATE_CONFIGURING);
-                    mDestinationSpinnerAdapter.pruneRemovedPrinters();
                     ensurePreviewUiShown();
                 }
 
@@ -2653,10 +2718,17 @@
             } else if (spinner == mMediaSizeSpinner) {
                 SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
+
+                MediaSize newMediaSize;
                 if (mOrientationSpinner.getSelectedItemPosition() == 0) {
-                    attributes.setMediaSize(mediaItem.value.asPortrait());
+                    newMediaSize = mediaItem.value.asPortrait();
                 } else {
-                    attributes.setMediaSize(mediaItem.value.asLandscape());
+                    newMediaSize = mediaItem.value.asLandscape();
+                }
+
+                if (newMediaSize != attributes.getMediaSize()) {
+                    clearRanges = true;
+                    attributes.setMediaSize(newMediaSize);
                 }
             } else if (spinner == mColorModeSpinner) {
                 SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position);
@@ -2668,25 +2740,35 @@
                 SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
                 if (mMediaSizeSpinner.getSelectedItem() != null) {
-                    if (orientationItem.value == ORIENTATION_PORTRAIT) {
-                        attributes.copyFrom(attributes.asPortrait());
-                    } else {
-                        attributes.copyFrom(attributes.asLandscape());
+                    boolean isPortrait = attributes.isPortrait();
+
+                    if (isPortrait != (orientationItem.value == ORIENTATION_PORTRAIT)) {
+                        clearRanges = true;
+                        if (orientationItem.value == ORIENTATION_PORTRAIT) {
+                            attributes.copyFrom(attributes.asPortrait());
+                        } else {
+                            attributes.copyFrom(attributes.asLandscape());
+                        }
                     }
                 }
             } else if (spinner == mRangeOptionsSpinner) {
                 if (mRangeOptionsSpinner.getSelectedItemPosition() == 0) {
+                    clearRanges = true;
                     mPageRangeEditText.setText("");
                 } else if (TextUtils.isEmpty(mPageRangeEditText.getText())) {
                     mPageRangeEditText.setError("");
                 }
             }
 
-            if (canUpdateDocument()) {
-                updateDocument(false);
+            if (clearRanges) {
+                clearPageRanges();
             }
 
             updateOptionsUi();
+
+            if (canUpdateDocument()) {
+                updateDocument(false);
+            }
         }
 
         @Override
@@ -2702,6 +2784,10 @@
             if (!TextUtils.isEmpty(editText.getText())) {
                 editText.setSelection(editText.getText().length());
             }
+
+            if (view == mPageRangeEditText && !hasFocus) {
+                updateSelectedPagesFromTextField();
+            }
         }
     }
 
@@ -2719,19 +2805,22 @@
         @Override
         public void afterTextChanged(Editable editable) {
             final boolean hadErrors = hasErrors();
-
             String text = editable.toString();
 
             if (TextUtils.isEmpty(text)) {
-                mPageRangeEditText.setError("");
-                updateOptionsUi();
+                if (mPageRangeEditText.getError() == null) {
+                    mPageRangeEditText.setError("");
+                    updateOptionsUi();
+                }
                 return;
             }
 
             String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
             if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
-                mPageRangeEditText.setError("");
-                updateOptionsUi();
+                if (mPageRangeEditText.getError() == null) {
+                    mPageRangeEditText.setError("");
+                    updateOptionsUi();
+                }
                 return;
             }
 
@@ -2747,8 +2836,10 @@
                 }
                 final int pageIndex = Integer.parseInt(numericString);
                 if (pageIndex < 1 || pageIndex > pageCount) {
-                    mPageRangeEditText.setError("");
-                    updateOptionsUi();
+                    if (mPageRangeEditText.getError() == null) {
+                        mPageRangeEditText.setError("");
+                        updateOptionsUi();
+                    }
                     return;
                 }
             }
@@ -2757,13 +2848,14 @@
             // greater than the to page. When computing the requested pages
             // we just swap them if necessary.
 
-            mPageRangeEditText.setError(null);
-            mPrintButton.setEnabled(true);
-            updateOptionsUi();
-
-            if (hadErrors && !hasErrors()) {
+            if (mPageRangeEditText.getError() != null) {
+                mPageRangeEditText.setError(null);
                 updateOptionsUi();
             }
+
+            if (hadErrors && canUpdateDocument()) {
+                updateDocument(false);
+            }
         }
     }
 
@@ -2783,8 +2875,10 @@
             final boolean hadErrors = hasErrors();
 
             if (editable.length() == 0) {
-                mCopiesEditText.setError("");
-                updateOptionsUi();
+                if (mCopiesEditText.getError() == null) {
+                    mCopiesEditText.setError("");
+                    updateOptionsUi();
+                }
                 return;
             }
 
@@ -2796,16 +2890,19 @@
             }
 
             if (copies < MIN_COPIES) {
-                mCopiesEditText.setError("");
-                updateOptionsUi();
+                if (mCopiesEditText.getError() == null) {
+                    mCopiesEditText.setError("");
+                    updateOptionsUi();
+                }
                 return;
             }
 
             mPrintJob.setCopies(copies);
 
-            mCopiesEditText.setError(null);
-
-            updateOptionsUi();
+            if (mCopiesEditText.getError() != null) {
+                mCopiesEditText.setError(null);
+                updateOptionsUi();
+            }
 
             if (hadErrors && canUpdateDocument()) {
                 updateDocument(false);
@@ -2820,29 +2917,50 @@
 
         private boolean mPosted;
 
+        /** State before run was executed */
+        private int mPreviousState = -1;
+
         public ProgressMessageController(Context context) {
             mHandler = new Handler(context.getMainLooper(), null, false);
         }
 
         public void post() {
-            if (mPosted) {
+            if (mState == STATE_UPDATE_SLOW) {
+                setState(STATE_UPDATE_SLOW);
+                ensureProgressUiShown();
+                updateOptionsUi();
+
+                return;
+            } else if (mPosted) {
                 return;
             }
+            mPreviousState = -1;
             mPosted = true;
             mHandler.postDelayed(this, PROGRESS_TIMEOUT_MILLIS);
         }
 
-        public void cancel() {
+        private int getStateAfterCancel() {
+            if (mPreviousState == -1) {
+                return mState;
+            } else {
+                return mPreviousState;
+            }
+        }
+
+        public int cancel() {
             if (!mPosted) {
-                return;
+                return getStateAfterCancel();
             }
             mPosted = false;
             mHandler.removeCallbacks(this);
+
+            return getStateAfterCancel();
         }
 
         @Override
         public void run() {
             mPosted = false;
+            mPreviousState = mState;
             setState(STATE_UPDATE_SLOW);
             ensureProgressUiShown();
             updateOptionsUi();
@@ -2991,12 +3109,10 @@
             List<PageRange> rangesToShred = new ArrayList<>();
             PageRange previousRange = null;
 
-            final int pageCount = printJob.getDocumentInfo().getPageCount();
-
             PageRange[] printedPages = printJob.getPages();
             final int rangeCount = printedPages.length;
             for (int i = 0; i < rangeCount; i++) {
-                PageRange range = PageRangeUtils.asAbsoluteRange(printedPages[i], pageCount);
+                PageRange range = printedPages[i];
 
                 if (previousRange == null) {
                     final int startPageIdx = 0;
@@ -3015,11 +3131,8 @@
                 }
 
                 if (i == rangeCount - 1) {
-                    final int startPageIdx = range.getEnd() + 1;
-                    final int endPageIdx = printJob.getDocumentInfo().getPageCount() - 1;
-                    if (startPageIdx <= endPageIdx) {
-                        PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
-                        rangesToShred.add(removedRange);
+                    if (range.getEnd() != Integer.MAX_VALUE) {
+                        rangesToShred.add(new PageRange(range.getEnd() + 1, Integer.MAX_VALUE));
                     }
                 }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index e53a522..cee16c8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -73,8 +73,9 @@
     private static final int LOADER_ID_PRINT_REGISTRY_INT = 2;
     private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 3;
 
-    public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
+    public static final String INTENT_EXTRA_PRINTER = "INTENT_EXTRA_PRINTER";
 
+    private static final String EXTRA_PRINTER = "EXTRA_PRINTER";
     private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
 
     private static final String KEY_NOT_FIRST_CREATE = "KEY_NOT_FIRST_CREATE";
@@ -134,7 +135,7 @@
                 if (printer == null) {
                     startAddPrinterActivity();
                 } else {
-                    onPrinterSelected(printer.getId());
+                    onPrinterSelected(printer);
                 }
             }
         });
@@ -244,7 +245,7 @@
                 MenuItem selectItem = menu.add(Menu.NONE, R.string.print_select_printer,
                         Menu.NONE, R.string.print_select_printer);
                 Intent intent = new Intent();
-                intent.putExtra(EXTRA_PRINTER_ID, printer.getId());
+                intent.putExtra(EXTRA_PRINTER, printer);
                 selectItem.setIntent(intent);
             }
 
@@ -263,8 +264,8 @@
     public boolean onContextItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.string.print_select_printer: {
-                PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
-                onPrinterSelected(printerId);
+                PrinterInfo printer = item.getIntent().getParcelableExtra(EXTRA_PRINTER);
+                onPrinterSelected(printer);
             } return true;
 
             case R.string.print_forget_printer: {
@@ -302,9 +303,9 @@
         super.onStop();
     }
 
-    private void onPrinterSelected(PrinterId printerId) {
+    private void onPrinterSelected(PrinterInfo printer) {
         Intent intent = new Intent();
-        intent.putExtra(INTENT_EXTRA_PRINTER_ID, printerId);
+        intent.putExtra(INTENT_EXTRA_PRINTER, printer);
         setResult(RESULT_OK, intent);
         finish();
     }
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 93415c0..9cf9dc9 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Laat loop WebView-leweraars in \'n geïsoleerde proses."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Hierdie keuse is nie meer geldig nie. Probeer weer."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Skakel om na lêerenkripsie"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Skakel om …"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Lêerenkripsie is reeds uitgevoer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index cf2a6ce..40e5a31 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"የWebView ምስል ሰሪዎችን በተገለለ ሂደት ውስጥ አሂድ።"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"የWebView ትግበራ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"የWebView ትግበራን ያዘጋጁ"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ይህ ምርጫ ከአሁን በኋላ የሚሰራ አይደለም። እንደገና ይሞክሩ።"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ወደ ፋይል ምሥጠራ ቀይር"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ለውጥ…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ፋይል አስቀድሞ ተመስጥሯል"</string>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 31d20a9..ca06e664 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView rendererləri təcrid olunmuş prosesdə işlədin."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView icrası"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView icrasını ayarlayın"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu seçim artıq etibarlı deyil. Yenidən cəhd edin."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Fayl şifrələnməsinə çevirin"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Çevirin..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl artıq şifrələnib"</string>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index ded4e41..ebb5a59 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запусціць апрацоўшчыкі WebView у ізаляваным працэсе."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Рэалізацыя WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Наладзіць рэалізацыю WebView"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Гэты элемент больш не даступны для выбару. Паспрабуйце яшчэ раз."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Перайсці на шыфраванне файлаў"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Пераход..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шыфраванне файлаў ужо дзейнічае"</string>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index dcce9a5..ce0f409 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrenite WebView operatera u izolovanom procesu."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Postavljanje WebViewa"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesi WebView"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više ne vrijedi. Pokušajte ponovo."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u šifrirani fajl"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvaranje…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fajl je već šifriran"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index a1393e8..1e67182 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"اجرای تولیدکننده تصویر وب‌نما در یک پردازش مجزا."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای وب‌نما"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای وب‌نما"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"این انتخاب دیگر معتبر نیست. دوباره امتحان کنید."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index afde9b5..23d83a2 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Գործարկել WebView-ի մշակիչները առանձնացված գործընթացում:"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-ի իրականացում"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ընտրեք WebView-ի իրականացումը"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Այս ընտրանքն այլևս վավեր չէ: Փորձեք նորից:"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Վերածել ֆայլային գաղտնագրման"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Փոխարկել…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ֆայլային գաղտնագրումն արդեն կատարվել է"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index b1d4eea..74ea372 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"הרץ מעבדי תצוגת אתר בהליך מבודד"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"‏יישום WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏הגדרת יישום WebView"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"אפשרות זו כבר אינה תקפה. נסה שוב."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"המר להצפנת קבצים"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"המר..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"הצפנת קבצים כבר מוגדרת"</string>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 1c05631..29e9459 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView ვიზუალიზატორების იზოლირებულ პროცესში გაშვება."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView რეალიზაცია"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView რეალიზაციის დაყენება"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"თქვენი არჩევანი აღარ მოქმედებს. ცადეთ ხელახლა."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ფაილების დაშიფვრაზე გარდაქმნა"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"გარდაქმნა…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"უკვე დაშიფრულია ფაილების დონეზე"</string>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 7c90cca..6d13b35 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ಪ್ರತ್ಯೇಕಗೊಳಿಸಿದ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ WebView ರೆಂಡರರ್‌‌ ರನ್‌ ಮಾಡಿ."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ಈ ಆಯ್ಕೆಯು ಇನ್ನು ಮುಂದೆ ಮಾನ್ಯವಾಗಿರುವುದಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ಫೈಲ್ ಎನ್‌ಕ್ರಿಪ್ಶನ್‌ಗೆ ಪರಿವರ್ತಿಸು"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ಪರಿವರ್ತಿಸು…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ಫೈಲ್ ಈಗಾಗಲೇ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 9956271..8c43312 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView рендерерлерин корголгон процессте иштетүү."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Тандалган нерсе жараксыз болуп калган. Кайра аракет кылыңыз."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index d6a28cd..a4b3877 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ഒറ്റപ്പെട്ടൊരു പ്രോസസ്സിൽ WebView റെൻഡററുകൾ റൺ ചെയ്യുക."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView നടപ്പാക്കൽ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ഈ തിരഞ്ഞെടുപ്പിന് തുടർന്നങ്ങോട്ട് സാധുതയില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ഫയൽ എൻക്രിപ്ഷനിലേക്ക് പരിവർത്തിപ്പിക്കുക"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"പരിവർത്തിപ്പിക്കുക…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ഇതിനകം തന്നെ ഫയൽ എൻക്രിപ്റ്റ് ചെയ്തു"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index eee940b..d363874 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एक वेगळ्या प्रक्रियेत WebView प्रस्तुतकर्ते चालवा."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबदृश्य अंमलबजावणी सेट करा"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ही निवड यापुढे वैध असणार नाही. पुन्हा प्रयत्न करा."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"फाईल कूटबद्धीकरणावर रूपांतरित करा"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करा..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फाईल आधीपासून कूटबद्ध केली"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 3f39931..a001cab 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"एउटा पृथक प्रक्रियामा वेबभ्यु रेन्डररहरू चलाउनुहोस्।"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट गर्नुहोस्"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"यो छनोट अब मान्य छैन। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"फाइल इन्क्रिप्सनमा रूपान्तरण गर्नुहोस्"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रुपान्तरण गर्नुहोस्…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"पहिल्यै फाइल इन्क्रिप्ट गरिएको छ"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 883fda0..c792ec9 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"ਕਿਸੇ ਵੱਖ ਕੀਤੀ ਗਈ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ WebView ਰੈਂਡਰਰਾਂ ਨੂੰ ਚਲਾਓ।"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ਅਮਲ"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ਅਮਲ ਸੈੱਟ ਕਰੋ"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ਇਹ ਚੋਣ ਹੁਣ ਵੈਧ ਨਹੀਂ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ਫ਼ਾਈਲ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕਰੋ"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index b3ead79..4c73219 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"හුදකලා වූ ක්‍රියාවලියක WebView විදහා දැක්වීම් ධාවනය කරන්න."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ක්‍රියාත්මක කිරීම"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ක්‍රියාත්මක කිරීම සකසන්න"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"මෙම තෝරා ගැනීම තව දුරටත් වලංගු නැත. නැවත උත්සාහ කරන්න."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"ගොනු සංකේතනයට පරිවර්තනය කරන්න"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"පරිවර්තනය කරන්න..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"දැනටමත් ගොනුව සංකේතනය කර ඇත"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 5d7b1a3..0f6f78c 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"เรียกใช้โหมดแสดงภาพ WebView ในการดำเนินการที่แยกออกมา"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"การใช้งาน WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ตั้งค่าการใช้งาน WebView"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"ตัวเลือกนี้ใช้ไม่ได้อีกต่อไป โปรดลองอีกครั้ง"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"แปลงเป็นการเข้ารหัสไฟล์"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"แปลง…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"เข้ารหัสไฟล์แล้ว"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 2311a66..ec04120 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -278,8 +278,7 @@
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView renderlovchilarini alohida jarayonda ishga tushirish."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ta’minotchisini sozlash"</string>
-    <!-- no translation found for select_webview_provider_toast_text (5466970498308266359) -->
-    <skip />
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Bu variant endi yaroqsiz. Qaytadan urining."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Faylli shifrga o‘girish"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"O‘girish…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl allaqachon shifrlangan"</string>
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
new file mode 100755
index 0000000..299a5b7
--- /dev/null
+++ b/packages/SettingsLib/res/values/config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+<resources>
+    <!-- Configuration for automotive -->
+    <bool name="enable_pbap_pce_profile">false</bool>
+</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 1f1a9b8..e86ca82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -78,7 +78,8 @@
         int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
         boolean enforcedByDeviceOwner = false;
         if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
-            Bundle enforcedRestrictions = dpm.getUserRestrictions(deviceOwner, deviceOwnerUserId);
+            Bundle enforcedRestrictions =
+                    dpm.getUserRestrictionsForUser(deviceOwner, deviceOwnerUserId);
             if (enforcedRestrictions != null
                     && enforcedRestrictions.getBoolean(userRestriction, false)) {
                 enforcedByDeviceOwner = true;
@@ -90,7 +91,8 @@
         if (userId != UserHandle.USER_NULL) {
             profileOwner = dpm.getProfileOwnerAsUser(userId);
             if (profileOwner != null) {
-                Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
+                Bundle enforcedRestrictions =
+                        dpm.getUserRestrictionsForUser(profileOwner, userId);
                 if (enforcedRestrictions != null
                         && enforcedRestrictions.getBoolean(userRestriction, false)) {
                     enforcedByProfileOwner = true;
@@ -234,7 +236,7 @@
             if (ipm.isPackageSuspendedForUser(packageName, userId)) {
                 return getProfileOrDeviceOwner(context, userId);
             }
-        } catch (RemoteException e) {
+        } catch (RemoteException | IllegalArgumentException e) {
             // Nothing to do
         }
         return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 6226b23..6052ccd 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -24,12 +24,14 @@
 import android.bluetooth.BluetoothMap;
 import android.bluetooth.BluetoothInputDevice;
 import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothPbapClient;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
 import android.content.Intent;
 import android.os.ParcelUuid;
 import android.util.Log;
+import com.android.settingslib.R;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -82,7 +84,9 @@
     private final HidProfile mHidProfile;
     private OppProfile mOppProfile;
     private final PanProfile mPanProfile;
+    private PbapClientProfile mPbapClientProfile;
     private final PbapServerProfile mPbapProfile;
+    private final boolean mUsePbapPce;
 
     /**
      * Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -99,6 +103,7 @@
         mLocalAdapter = adapter;
         mDeviceManager = deviceManager;
         mEventManager = eventManager;
+        mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
         // pass this reference to adapter and event manager (circular dependency)
         mLocalAdapter.setProfileManager(this);
         mEventManager.setProfileManager(this);
@@ -205,9 +210,24 @@
         } else if (mOppProfile != null) {
             Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
         }
+
+        //PBAP Client
+        if (mUsePbapPce) {
+            if (mPbapClientProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
+                mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager,
+                        this);
+                addProfile(mPbapClientProfile, PbapClientProfile.NAME,
+                        BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mPbapClientProfile != null) {
+            Log.w(TAG,
+                "Warning: PBAP Client profile was previously added but the UUID is now missing.");
+        }
+
         mEventManager.registerProfileIntentReceiver();
 
-        // There is no local SDP record for HID and Settings app doesn't control PBAP
+        // There is no local SDP record for HID and Settings app doesn't control PBAP Server.
     }
 
     private final Collection<ServiceListener> mServiceListeners =
@@ -351,6 +371,10 @@
         }
     }
 
+    public PbapClientProfile getPbapClientProfile() {
+        return mPbapClientProfile;
+    }
+
     public PbapServerProfile getPbapProfile(){
         return mPbapProfile;
     }
@@ -430,6 +454,12 @@
             removedProfiles.remove(mMapProfile);
             mMapProfile.setPreferred(device, true);
         }
-    }
 
+        if (mUsePbapPce) {
+            profiles.add(mPbapClientProfile);
+            removedProfiles.remove(mPbapClientProfile);
+            profiles.remove(mPbapProfile);
+            removedProfiles.add(mPbapProfile);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
new file mode 100755
index 0000000..aa95be2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -0,0 +1,233 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+final class PbapClientProfile implements LocalBluetoothProfile {
+    private static final String TAG = "PbapClientProfile";
+    private static boolean V = false;
+
+    private BluetoothPbapClient mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+
+    static final ParcelUuid[] SRC_UUIDS = {
+        BluetoothUuid.PBAP_PSE,
+    };
+
+    static final String NAME = "PbapClient";
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 6;
+
+    // These callbacks run on the main thread.
+    private final class PbapClientServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) {
+                Log.d(TAG,"Bluetooth service connected");
+            }
+            mService = (BluetoothPbapClient) proxy;
+            // We just bound to the service, so refresh the UI for any connected PBAP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "PbapClientProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(PbapClientProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady = true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) {
+                Log.d(TAG,"Bluetooth service disconnected");
+            }
+            mIsProfileReady = false;
+        }
+    }
+
+    private void refreshProfiles() {
+        Collection<CachedBluetoothDevice> cachedDevices = mDeviceManager.getCachedDevicesCopy();
+        for (CachedBluetoothDevice device : cachedDevices) {
+            device.onUuidChanged();
+        }
+    }
+
+    public boolean pbapClientExists() {
+        return (mService != null);
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    PbapClientProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new PbapClientServiceListener(),
+                BluetoothProfile.PBAP_CLIENT);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) {
+            return new ArrayList<BluetoothDevice>(0);
+        }
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (V) {
+            Log.d(TAG,"PBAPClientProfile got connect request");
+        }
+        if (mService == null) {
+            return false;
+        }
+        List<BluetoothDevice> srcs = getConnectedDevices();
+        if (srcs != null) {
+            for (BluetoothDevice src : srcs) {
+                if (src.equals(device)) {
+                    // Connect to same device, Ignore it
+                    Log.d(TAG,"Ignoring Connect");
+                    return true;
+                }
+            }
+            mService.disconnect(device);
+        }
+        Log.d(TAG,"PBAPClientProfile attempting to connect to " + device.getAddress());
+
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (V) {
+            Log.d(TAG,"PBAPClientProfile got disconnect request");
+        }
+        if (mService == null) {
+            return false;
+        }
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) {
+            return false;
+        }
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.PRIORITY_OFF;
+        }
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) {
+            return;
+        }
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        // we need to have same string in UI as the server side.
+        return R.string.bluetooth_profile_pbap;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return R.string.bluetooth_profile_pbap_summary;
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_cellphone;
+    }
+
+    protected void finalize() {
+        if (V) {
+            Log.d(TAG, "finalize()");
+        }
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
+                    BluetoothProfile.PBAP_CLIENT,mService);
+                mService = null;
+            } catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up PBAP Client proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 987b5ea..61c9f2b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -21,6 +21,7 @@
 import android.app.AppGlobals;
 import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.content.Context;
@@ -63,6 +64,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.providers.settings.SettingsState.Setting;
+import com.android.server.SystemConfig;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -1940,7 +1942,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 125;
+            private static final int SETTINGS_VERSION = 126;
 
             private final int mUserId;
 
@@ -2136,6 +2138,35 @@
                     currentVersion = 125;
                 }
 
+                if (currentVersion == 125) {
+                    // Version 125: Allow OEMs to set the default VR service.
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+                    Setting currentSetting = secureSettings.getSettingLocked(
+                            Settings.Secure.ENABLED_VR_LISTENERS);
+                    if (currentSetting == null) {
+                        ArraySet<ComponentName> l =
+                                SystemConfig.getInstance().getDefaultVrComponents();
+
+                        if (l != null && !l.isEmpty()) {
+                            StringBuilder b = new StringBuilder();
+                            boolean start = true;
+                            for (ComponentName c : l) {
+                                if (!start) {
+                                    b.append(':');
+                                }
+                                b.append(c.flattenToString());
+                                start = false;
+                            }
+                            secureSettings.insertSettingLocked(
+                                    Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
+
+                    }
+                    currentVersion = 126;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 // Return the current version.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0c35573..b557dc4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -139,7 +139,7 @@
 
         <activity
             android:name=".BugreportWarningActivity"
-            android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+            android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true"
             android:exported="false" />
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 49759c5..814aa8c 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -56,7 +56,7 @@
         final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
         final RowBuilder row = result.newRow();
         row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED);
         row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon);
         row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title));
         row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
similarity index 78%
rename from packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
index 89e4aac..ebc6a4a7 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_gain_animation.xml
@@ -17,13 +17,13 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android">
 
     <objectAnimator
-        android:propertyName="translationY"
-        android:valueTo="10dp"
-        android:interpolator="@android:interpolator/linear_out_slow_in"
+        android:propertyName="scaleX"
+        android:valueTo="1.0"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
         android:duration="@integer/recents_tv_pip_focus_anim_duration" />
     <objectAnimator
-        android:propertyName="alpha"
+        android:propertyName="scaleY"
         android:valueTo="1.0"
-        android:interpolator="@android:interpolator/linear_out_slow_in"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
         android:duration="@integer/recents_tv_pip_focus_anim_duration" />
 </set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
similarity index 76%
copy from packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
copy to packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
index 89e4aac..95499bd 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_in.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_buttons_in_recents_focus_lose_animation.xml
@@ -17,13 +17,13 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android">
 
     <objectAnimator
-        android:propertyName="translationY"
-        android:valueTo="10dp"
-        android:interpolator="@android:interpolator/linear_out_slow_in"
+        android:propertyName="scaleX"
+        android:valueTo="0.7"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
         android:duration="@integer/recents_tv_pip_focus_anim_duration" />
     <objectAnimator
-        android:propertyName="alpha"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/linear_out_slow_in"
+        android:propertyName="scaleY"
+        android:valueTo="0.7"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
         android:duration="@integer/recents_tv_pip_focus_anim_duration" />
 </set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml b/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
deleted file mode 100644
index c73fed6..0000000
--- a/packages/SystemUI/res/anim/tv_pip_controls_fade_out.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <objectAnimator
-        android:propertyName="translationY"
-        android:valueTo="0dp"
-        android:interpolator="@android:interpolator/fast_out_linear_in"
-        android:duration="@integer/recents_tv_pip_focus_anim_duration" />
-    <objectAnimator
-        android:propertyName="alpha"
-        android:valueTo="0.0"
-        android:interpolator="@android:interpolator/fast_out_linear_in"
-        android:duration="@integer/recents_tv_pip_focus_anim_duration" />
-</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..7555bdd
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="translationY"
+    android:valueTo="0dp"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..b40ccd4
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="translationY"
+    android:valueTo="-57dp"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
new file mode 100644
index 0000000..681ff91
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="1"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
new file mode 100644
index 0000000..e6deb0f
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="0"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
deleted file mode 100644
index 7b0fcc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
deleted file mode 100644
index 73e9c96..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
deleted file mode 100644
index a02e21c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
deleted file mode 100644
index 4af2617..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
deleted file mode 100644
index 24bdbb6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
deleted file mode 100644
index 6ecd2d3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
deleted file mode 100644
index 5e733ef..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
deleted file mode 100644
index ecc2c83..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_notify_image_error.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
new file mode 100644
index 0000000..4d2a35e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -0,0 +1,45 @@
+<!--
+    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="26.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M0 0h26v24H0z"
+        android:fillColor="#00000000"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M21.0,8.5
+        c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
+        C25.1,5.96 20.26,2.0 13.0,2.0
+        S0.9,5.9 0.42,6.32
+        l12.57,15.6 4.21,-5.17
+        c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25
+        c0.0,-2.76 2.24,-5.0 5.0,-5.0z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M21.0,10.0
+        c-1.93,0.0 -3.5,1.57 -3.5,3.5l1.75,0.0
+        c0.0,-0.9 0.78,-1.75 1.75,-1.75s1.7,0.78 1.75,1.75
+        c0.0,0.48 -0.2,0.92 -0.51,1.24l-1.09,1.1
+        c-0.6,0.63 -1.02,1.51 -1.02,2.47l0.0,0.44l1.75,0.0
+        c0.0,-1.3 0.39,-1.84 1.03,-2.47l0.78,-0.8
+        c0.5,-0.5 0.82,-1.2 0.82,-1.97
+        C24.5,11.57 22.93,10.0 21.0,10.0z
+        m-0.95,11.95l1.9,0.0l0.0,-1.9l-1.9,0.0l0.0,1.9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_notify_image.xml b/packages/SystemUI/res/drawable/stat_notify_image.xml
new file mode 100644
index 0000000..c8745d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image.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:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z
+M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5 L8.5,13.5z" />
+    <path
+        android:pathData="M0,0h24v24H0V0z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image_error.xml b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
new file mode 100644
index 0000000..b929005
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_notify_image_error.xml
@@ -0,0 +1,30 @@
+<!--
+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="M0,0h24v24H0V0z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M17,18H5l3.5-4.5l2.5,3l3.3-4.5l2.7,3.8V8h4V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h12V18z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.2,21H21v-1.8h-1.8V21z M19.2,9.9v7.4H21V9.9H19.2z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 5cabb77..405ea0c 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -17,8 +17,8 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="oval">
     <size
-        android:width="36dp"
-        android:height="36dp" />
+        android:width="34dp"
+        android:height="34dp" />
     <solid
         android:color="#4DFFFFFF" />
 </shape>
diff --git a/packages/SystemUI/res/layout/qs_customize_tile_divider.xml b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
new file mode 100644
index 0000000..0d932ac
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_customize_tile_divider.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<View
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="16dp"
+    android:layout_marginEnd="16dp"
+    android:background="?android:attr/listDivider"
+    android:importantForAccessibility="no" />
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index 0f8c77c..28ea66d 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -31,18 +31,12 @@
         android:focusable="true"
         android:layoutDirection="rtl" />
 
+    <!-- Placeholder view to give focus to the PIP menus. -->
     <View
-        android:id="@+id/pip_shade"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone"
-        android:background="#76000000" />
-
-    <include
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:layout_marginTop="132dp"
-        layout="@layout/tv_pip_controls" />
+        android:id="@+id/pip"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:focusable="true"
+        android:visibility="gone" />
 
 </com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml
index 2b2ce4e..625e9c1 100644
--- a/packages/SystemUI/res/layout/recents_stack_action_button.xml
+++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml
@@ -18,7 +18,6 @@
     android:id="@+id/button"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:gravity="start|center_vertical"
     android:paddingStart="14dp"
     android:paddingEnd="14dp"
     android:paddingTop="12dp"
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
index 2e0c9e7..563441f 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -17,13 +17,8 @@
 */
 -->
 
-<com.android.systemui.tv.pip.PipControlsView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/pip_controls"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:orientation="horizontal">
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <LinearLayout
         android:layout_width="100dp"
@@ -98,4 +93,4 @@
             android:textSize="12sp"
             android:textColor="#EEEEEE" />
     </LinearLayout>
-</com.android.systemui.tv.pip.PipControlsView>
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index c2c83ff..2647a99 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -26,7 +26,8 @@
     android:gravity="top|center_horizontal"
     android:clipChildren="false">
 
-    <include
-        layout="@layout/tv_pip_controls"
-        android:clipChildren="false" />
+    <com.android.systemui.tv.pip.PipControlsView
+        android:id="@+id/pip_controls"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index c5c7e84..64bf3b5 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -38,25 +38,4 @@
         android:gravity="center"
         android:maxLines="2"
         android:text="@string/pip_hold_home" />
-    <LinearLayout
-        android:id="@+id/guide_buttons"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        android:orientation="horizontal">
-        <ImageView
-            android:layout_width="19dp"
-            android:layout_height="19dp"
-            android:src="@drawable/ic_fullscreen_white_24dp" />
-        <ImageView
-            android:layout_width="19dp"
-            android:layout_height="19dp"
-            android:src="@drawable/ic_close_white" />
-        <ImageView
-            android:id="@+id/guide_button_play_pause"
-            android:layout_width="19dp"
-            android:layout_height="19dp"
-            android:src="@drawable/ic_pause_white_24dp" />
-    </LinearLayout>
 </RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
new file mode 100644
index 0000000..1e464d8
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="top|center_horizontal">
+
+    <com.android.systemui.tv.pip.PipRecentsControlsView
+        android:id="@+id/pip_controls"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent" />
+
+    <View
+        android:id="@+id/recents"
+        android:layout_width="1dp"
+        android:layout_height="1dp"
+        android:focusable="true" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5e6c5f7..47d3bff 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Kies Sleutelbordknoppie"</string>
     <string name="preview" msgid="9077832302472282938">"Voorskou"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Sleep om teëls by te voeg"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hierheen om te verwyder"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Wysig"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Tyd"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Skuif op"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Skuif links"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Skuif regs"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Program sal dalk nie met multivenster werk nie"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dubbeltik om te wysig."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dubbeltik om by te voeg."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>. Dubbeltik om te kies."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Skuif <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Verwyder <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is by posisie <xliff:g id="POSITION">%2$d</xliff:g> gevoeg"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verwyder"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is na posisie <xliff:g id="POSITION">%2$d</xliff:g> geskuif"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kitsinstellingswysiger."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 3537b97..f2afb8f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"የቁልፍ ሰሌዳ አዝራር ይምረጡ"</string>
     <string name="preview" msgid="9077832302472282938">"ቅድመ-እይታ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ሰቆችን ለማከል ይጎትቱ"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ለማስወገድ ወደዚህ ይጎትቱ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"አርትዕ"</string>
     <string name="tuner_time" msgid="6572217313285536011">"ሰዓት"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ወደ ላይ ሂድ"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ወደ ግራ ሂድ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ወደ ቀኝ ሂድ"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"መተግበሪያ ከብዝሃ-መስኮት ጋር ላይሠራ ይችላል"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ቦታ <xliff:g id="POSITION">%1$d</xliff:g>፣ <xliff:g id="TILE_NAME">%2$s</xliff:g>። ለማርትዕ ሁለቴ መታ ያድርጉ።"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>። ለማከል ሁለቴ መታ ያድርጉ።"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ቦታ <xliff:g id="POSITION">%1$d</xliff:g>። ለመምረጥ ሁለቴ መታ ያድርጉ።"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ን ይውሰዱ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ን ያስወግዱ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ወደ ቦታ <xliff:g id="POSITION">%2$d</xliff:g> ታክሏል"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ተወግዷል"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ወደ ቦታ <xliff:g id="POSITION">%2$d</xliff:g> ተወስዷል"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"የፈጣን ቅንብሮች አርታዒ።"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1b05192..f949eaf 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -587,4 +587,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"نقل لليسار"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"نقل لليمين"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"يمكن ألا يعمل التطبيق مع وضع النوافذ المتعددة."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"الموضع <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>. انقر نقرًا مزدوجًا للتعديل."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. انقر نقرًا مزدوجًا للإضافة."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"الموضع <xliff:g id="POSITION">%1$d</xliff:g>. انقر نقرًا مزدوجًا للتحديد."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"نقل <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"إزالة <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"تمت إضافة <xliff:g id="TILE_NAME">%1$s</xliff:g> إلى الموضع <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"تمت إزالة <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"تم نقل <xliff:g id="TILE_NAME">%1$s</xliff:g> إلى الموضع <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"برنامج تعديل الإعدادات السريعة."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index bd7572f..3aa911f 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klaviatura Düyməsi Seçin"</string>
     <string name="preview" msgid="9077832302472282938">"Önizləmə"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Xanalar əlavə etmək üçün sürüşdürün"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Silmək üçün bura sürüşdürün"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Redaktə edin"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Vaxt"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola köçürün"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa köçürün"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Tətbiq çoxsaylı pəncərə ilə işləməyə bilər."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Redaktə etmək üçün iki dəfə tıklayın."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Əlavə etmək üçün iki dəfə tıklayın."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi. Seçmək üçün iki dəfə tıklayın."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> köçürün"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> silin"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> mövqeyinə əlavə edildi"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> silindi"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> mövqeyinə köçürüldü"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sürətli ayarlar redaktoru."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 4935d99..cc091f6 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -583,6 +583,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomeri ulevo"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomeri udesno"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće funkcionisati sa više prozora"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite da biste izmenili."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dvaput dodirnite da biste dodali."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija. Dvaput dodirnite da biste izabrali."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premesti pločicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni pločicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je dodata na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjena"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je premeštena na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač za Brza podešavanja."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 9a3fc33..a496330 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -519,7 +519,7 @@
     <string name="keyboard_key_media_next" msgid="1894394911630345607">"Наступны"</string>
     <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Папярэдні"</string>
     <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Перамотка назад"</string>
-    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перамотка наперад"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Перамотка ўперад"</string>
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
     <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
@@ -567,8 +567,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Выберыце клавішу клавіятуры"</string>
     <string name="preview" msgid="9077832302472282938">"Папярэдні прагляд"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Перацягніце, каб дадаць пліткі"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перацягніце сюды, каб выдаліць"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Рэдагаваць"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Час"</string>
   <string-array name="clock_options">
@@ -587,6 +586,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перамясціць уверх"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перамясціць улева"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перамясціць управа"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Праграма можа не працаваць у рэжыме некалькіх вокнаў"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Краніце двойчы, каб рэдагаваць."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>, краніце двойчы, каб дадаць."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>. Краніце двойчы, каб выбраць."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перамясціць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Выдаліць <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дададзена ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> выдалена"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> перамешчана ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Рэдактар хуткіх налад."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 17e9f690..1479bea 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместване наляво"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместване надясно"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Приложението може да не работи в режим за няколко прозореца"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>, „<xliff:g id="TILE_NAME">%2$s</xliff:g>“. Докоснете двукратно, за да редактирате."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"„<xliff:g id="TILE_NAME">%1$s</xliff:g>“. Докоснете двукратно, за да добавите."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>. Докоснете двукратно, за да изберете."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Преместване на „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Премахване на „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Добавихте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ към позиция <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Премахнахте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Преместихте „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ на позиция <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор за бързи настройки."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 068e1c1..ed8b066 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"উপরে সরান"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বাঁয়ে সরান"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ডানে সরান"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"একাধিক-উইন্ডো দিয়ে অ্যাপ কাজ নাও করতে পারে"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> অবস্থান, <xliff:g id="TILE_NAME">%2$s</xliff:g>৷ সম্পাদনা করতে দুবার আলতো চাপুন৷"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>৷ যোগ করতে দুবার আলতো চাপুন৷"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> অবস্থান৷ নির্বাচন করতে দুবার আলতো চাপুন৷"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> সরান"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> সরান"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> অবস্থানে <xliff:g id="TILE_NAME">%1$s</xliff:g> যোগ করা হয়েছে"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> মোছা হয়েছে"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> এ সরানো হয়েছে"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"দ্রুত সেটিংস সম্পাদক৷"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 728c874..c620178 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -564,8 +564,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Odaberite dugme na tastaturi"</string>
     <string name="preview" msgid="9077832302472282938">"Pregledaj"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali polja"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovdje za uklanjanje"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
   <string-array name="clock_options">
@@ -585,4 +584,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomjeri lijevo"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomjeri desno"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće raditi s višestrukim prozorom"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite za uređivanje."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> Dvaput dodirnite za dodavanje."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>. Dvaput dodirnite za odabir."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pomjeri <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je dodan na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjen"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je premješten na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivanje brzih postavki"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 352e132..0145c2a 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -518,10 +518,10 @@
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avança ràpidament"</string>
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pàg"</string>
     <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pàg"</string>
-    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Suprimeix"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Tecla de supressió"</string>
     <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inici"</string>
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"Final"</string>
-    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insereix"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Tecla d\'inserció"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueig de teclat numèric"</string>
     <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclat numèric <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistema"</string>
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mou a l\'esquerra"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mou a la dreta"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"És possible que l\'aplicació no funcioni amb el Mode multifinestra"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posició <xliff:g id="POSITION">%1$d</xliff:g>, mosaic <xliff:g id="TILE_NAME">%2$s</xliff:g>. Fes doble toc per editar-la."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g>. Fes doble toc per afegir-lo."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posició <xliff:g id="POSITION">%1$d</xliff:g>. Fes doble toc per seleccionar-la."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mou el mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Suprimeix el mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"El mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha afegit a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"El mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha suprimit"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"El mosaic <xliff:g id="TILE_NAME">%1$s</xliff:g> s\'ha mogut a la posició <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de la configuració ràpida."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ea8ae38..ec2011f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -584,6 +584,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Přesunout nahoru"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Přesunout vlevo"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Přesunout vpravo"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikace nemusí v režimu několika oken fungovat."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvojitým klepnutím ji upravíte."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dlaždici přidáte dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>. Dvojitým klepnutím ji vyberete."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Přesunout dlaždici <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstranit dlaždici <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla přidána na pozici <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla odstraněna"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Dlaždice <xliff:g id="TILE_NAME">%1$s</xliff:g> byla přesunuta na pozici <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor rychlého nastavení"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index b6c2b73..8711100 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flyt op"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flyt til venstre"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flyt til højre"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerer muligvis ikke i Multivindue"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tryk to gange for at redigere."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tryk to gange for at tilføje."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Tryk to gange for at vælge."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjern <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> føjes til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> fjernes"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> blev flyttet til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 922939e..2daa00f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Nach links verschieben"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Nach rechts verschieben"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"App funktioniert im Mehrfenstermodus möglicherweise nicht"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Zum Bearbeiten doppeltippen."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Zum Hinzufügen doppeltippen."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Zum Auswählen doppeltippen."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verschieben"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> entfernen"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ist auf Position <xliff:g id="POSITION">%2$d</xliff:g> hinzugefügt worden"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> wurde entfernt"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> an Position <xliff:g id="POSITION">%2$d</xliff:g> verschoben"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor für Schnelleinstellungen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 7a23ac9..34385f3 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Μετακίνηση αριστερά"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Μετακίνηση δεξιά"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Η εφαρμογή ενδέχεται να μη λειτουργεί με τη λειτουργία πολλαπλών παραθύρων"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Πατήστε δύο φορές για επεξεργασία."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Πατήστε δύο φορές για προσθήκη."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>. Πατήστε δύο φορές για επιλογή."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Μετακίνηση <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Κατάργηση <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> προστέθηκε στη θέση <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> καταργείται"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Το <xliff:g id="TILE_NAME">%1$s</xliff:g> μετακινήθηκε στη θέση <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 6f4ae7b..71a8ad7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 6f4ae7b..71a8ad7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 6f4ae7b..71a8ad7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Move to the left"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Move to the right"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"App may not work with multi-window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Double tap to edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Double tap to add."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Double tap to select."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is added to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is removed"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moved to position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Quick settings editor."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9106592..35d0f47 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -508,7 +508,7 @@
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Centro"</string>
     <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulación"</string>
     <string name="keyboard_key_space" msgid="2499861316311153293">"Espacio"</string>
-    <string name="keyboard_key_enter" msgid="5739632123216118137">"Ingresar"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Intro"</string>
     <string name="keyboard_key_backspace" msgid="1559580097512385854">"Retroceso"</string>
     <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Reproducir/pausar"</string>
     <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Detener"</string>
@@ -516,11 +516,11 @@
     <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
     <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Retroceder"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avanzar rápido"</string>
-    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Página anterior"</string>
-    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Página siguiente"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pág"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pág"</string>
     <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Borrar"</string>
     <string name="keyboard_key_move_home" msgid="2765693292069487486">"Página principal"</string>
-    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Finalizar"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
     <string name="keyboard_key_insert" msgid="8530501581636082614">"Insertar"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Bloqueo numérico"</string>
     <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Teclado numérico <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la app no funcione con la función Multiventana"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Presiona dos veces para editarla."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Presiona dos veces para agregarlo."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Presiona dos veces para seleccionarla."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Quitar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Se agregó <xliff:g id="TILE_NAME">%1$s</xliff:g> a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Se quitó <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Se movió <xliff:g id="TILE_NAME">%1$s</xliff:g> a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de Configuración rápida"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c2f3a3a..a976a9c 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -516,8 +516,8 @@
     <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Anterior"</string>
     <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Rebobinar"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Avance rápido"</string>
-    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Retroceder página"</string>
-    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Avanzar página"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Re Pág"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Av Pág"</string>
     <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Supr"</string>
     <string name="keyboard_key_move_home" msgid="2765693292069487486">"Inicio"</string>
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"Fin"</string>
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover a la izquierda"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover a la derecha"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Es posible que la aplicación no funcione con el modo multiventana"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toca dos veces para cambiarla."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toca dos veces para añadirlo."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Toca dos veces para seleccionarla."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Quitar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha añadido a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha quitado"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> se ha movido a la posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de ajustes rápidos."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 0524d3b..e7bfdff 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Liigu üles"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Liigu vasakule"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Liigu paremale"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Rakendus ei pruugi mitme akna režiimis töötada"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Asend <xliff:g id="POSITION">%1$d</xliff:g>, paan <xliff:g id="TILE_NAME">%2$s</xliff:g>. Topeltpuudutage muutmiseks."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Topeltpuudutage lisamiseks."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Asend <xliff:g id="POSITION">%1$d</xliff:g>. Topeltpuudutage valimiseks."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Paani <xliff:g id="TILE_NAME">%1$s</xliff:g> teisaldamine"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Paani <xliff:g id="TILE_NAME">%1$s</xliff:g> eemaldamine"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> lisati asendisse <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> eemaldati"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Paan <xliff:g id="TILE_NAME">%1$s</xliff:g> teisaldati asendisse <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kiirseadete redigeerija."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 2e207c1..b9cb78e 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Eraman gora"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Eraman ezkerrera"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Eraman eskuinera"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Baliteke aplikazioak ez funtzionatzea leiho anitzetan."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. posizioa, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Editatzeko, sakatu birritan."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Gehitzeko, sakatu birritan."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. posizioa. Hautatzeko, sakatu birritan."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mugitu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Kendu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> gehitu da <xliff:g id="POSITION">%2$d</xliff:g>. posizioan"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Kendu da <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>. posiziora eraman da"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ezarpen bizkorren editorea."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 777fd2b..af74435 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"کلید صفحه‌کلید را انتخاب کنید"</string>
     <string name="preview" msgid="9077832302472282938">"پیش‌نمایش"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"کشیدن برای افزودن کاشی‌ها"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"برای حذف، به اینجا بکشید"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ویرایش"</string>
     <string name="tuner_time" msgid="6572217313285536011">"زمان"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"انتقال به چپ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"انتقال به راست"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"برنامه ممکن است با چندپنجره کار نکند"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>. برای ویرایش دو ضربه سریع بزنید."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. برای افزودن دو ضربه سریع بزنید."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>. برای انتخاب دو ضربه سریع بزنید."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"انتقال <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"حذف <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> به موقعیت <xliff:g id="POSITION">%2$d</xliff:g> اضافه می‌شود"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> حذف می‌شود"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> به موقعیت <xliff:g id="POSITION">%2$d</xliff:g> منتقل شد"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ویرایشگر تنظیمات سریع."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f100d21..3b28199 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Siirrä ylöspäin"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Siirrä vasemmalle"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Siirrä oikealle"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Sovellus ei ehkä toimi usean ikkunan tilassa."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Muokkaa kaksoisnapauttamalla."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lisää kaksoisnapauttamalla."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>. Valitse kaksoisnapauttamalla."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Siirrä <xliff:g id="TILE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Poista <xliff:g id="TILE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> lisättiin paikkaan <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> poistettiin."</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> siirrettiin paikkaan <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Pika-asetusten muokkausnäkymä"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1bec7fd..2ef24db 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Il est possible que l\'application ne fonctionne pas en mode Multi-fenêtre."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Touchez deux fois pour modifier."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Touchez deux fois pour ajouter."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position : <xliff:g id="POSITION">%1$d</xliff:g>. Touchez deux fois pour sélectionner."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Déplacer <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Supprimer <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été ajouté à la position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été supprimé"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> a été déplacé à la position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Éditeur de paramètres rapides."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index bb22848..93d9e14 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Déplacer vers la gauche"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Déplacer vers la droite"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Il est possible que l\'application ne fonctionne pas en mode multifenêtre."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, \"<xliff:g id="TILE_NAME">%2$s</xliff:g>\". Appuyer deux fois pour modifier."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Appuyer deux fois pour ajouter."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Appuyer deux fois pour sélectionner."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Déplacer \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Supprimer \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été ajouté à la position <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été supprimé."</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Le bloc \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" a bien été déplacé à la position <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Éditeur de configuration rapide."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 6d4b7eb..86a0bfa 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover á esquerda"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover á dereita"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Pode que a aplicación non funcione con varias ventás."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posición <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toca dúas veces o elemento para editalo."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toca dúas veces o elemento para engadilo"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posición <xliff:g id="POSITION">%1$d</xliff:g>. Toca dúas veces o elemento para seleccionalo."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Elimina <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> engadiuse á posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Eliminouse <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> moveuse á posición <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configuración rápida."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 5b68088..d52226d 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ઉપર ખસેડો"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ડાબે ખસેડો"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"જમણે ખસેડો"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"બહુ-વિંડો સાથે અ‍ૅપ્લિકેશન કદાચ કામ ન કરે"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"સ્થિતિ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. સંપાદિત કરવા માટે બે વાર ટૅપ કરો."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ઉમેરવા માટે બે વાર ટૅપ કરો."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"સ્થિતિ <xliff:g id="POSITION">%1$d</xliff:g>. પસંદ કરવા માટે બે વાર ટૅપ કરો."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ખસેડો"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> દૂર કરો"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> સ્થિતિ પર <xliff:g id="TILE_NAME">%1$s</xliff:g> ઉમેર્યું છે"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> દૂર કરવામાં આવ્યું છે"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ને <xliff:g id="POSITION">%2$d</xliff:g> સ્થિતિ પર ખસેડ્યું"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ઝડપી સેટિંગ્સ સંપાદક."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 44c0dbc..160d4a0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाएं ले जाएं"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दाएं ले जाएं"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"हो सकता है कि ऐप्लिकेशन एकाधिक विंडो के साथ काम ना करे"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करने के लिए डबल टैप करें."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. जोड़ने के लिए डबल टैप करें."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>. चुनने के लिए डबल टैप करें."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को ले जाएं"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> निकालें"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को <xliff:g id="POSITION">%2$d</xliff:g> स्थिति में जोड़ा गया"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> निकाल दिया गया है"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> को <xliff:g id="POSITION">%2$d</xliff:g> स्थिति में ले जाया गया"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"त्वरित सेटिंग संपादक."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index c3d6a24..ddfcb55 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -584,4 +584,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomakni ulijevo"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomakni udesno"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija možda neće funkcionirati uz više prozora"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dodirnite dvaput da biste uredili."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dodirnite dvaput da biste dodali."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>. Dodirnite dvaput da biste odabrali."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premjesti <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ukloni <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> dodana je na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> uklonjena"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> premještena je na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač brzih postavki."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 40fb3e23..c026926 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mozgatás balra"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mozgatás jobbra"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Lehet, hogy az alkalmazás nem működik többablakos nézetben"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozíció: <xliff:g id="TILE_NAME">%2$s</xliff:g>. Koppintson duplán a szerkesztéshez."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Koppintson duplán a hozzáadáshoz."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozíció. Koppintson duplán a kiválasztáshoz."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> áthelyezése"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> eltávolítása"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> hozzáadva <xliff:g id="POSITION">%2$d</xliff:g>. pozícióban"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> eltávolítva"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"A(z) <xliff:g id="TILE_NAME">%1$s</xliff:g> áthelyezve a(z) <xliff:g id="POSITION">%2$d</xliff:g>. pozícióba"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Gyorsbeállítások szerkesztője"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index a2e45e1..a9d122a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Ընտրեք ստեղնաշարի կոճակը"</string>
     <string name="preview" msgid="9077832302472282938">"Նախադիտում"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Քաշեք՝ սալիկներ ավելացնելու համար"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Քաշեք այստեղ՝ հեռացնելու համար"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Փոփոխել"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Ժամ"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Տեղափոխել վերև"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Տեղափոխել ձախ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Տեղափոխել աջ"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Հավելվածը չի կարող աշխատել բազմապատուհան ռեժիմում"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>: Կրկնակի հպեք՝ փոխելու համար:"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>: Կրկնակի հպեք՝ ավելացնելու համար:"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>: Կրկնակի հպեք՝ ընտրելու համար:"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Տեղափոխել <xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Հեռացնել <xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկն ավելացվել է <xliff:g id="POSITION">%2$d</xliff:g> դիրքին"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը հեռացվել է"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> սալիկը տեղափոխվել է դեպի <xliff:g id="POSITION">%2$d</xliff:g> դիրք"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Արագ կարգավորումների խմբագրիչ:"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index cad0e22..876034c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pindahkan ke kiri"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pindahkan ke kanan"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikasi mungkin tidak berfungsi dengan multi-jendela"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Ketuk dua kali untuk mengedit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Ketuk dua kali untuk menambahkan."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>. Ketuk dua kali untuk memilih."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pindahkan <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Hapus <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ditambahkan ke posisi <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dihapus"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dpindahkan ke posisi <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor setelan cepat."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index f609800..4ce5f54 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Færa upp"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Færa til vinstri"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Færa til hægri"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Hugsanlegt er að forritið virki ekki í mörgum gluggum"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Staða <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Ýttu tvisvar til að breyta."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Ýttu tvisvar til að bæta við."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Staða <xliff:g id="POSITION">%1$d</xliff:g>. Ýttu tvisvar til að velja."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Færa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjarlægja <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er bætt við í stöðu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> var fjarlægð"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> færð í stöðu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Flýtistillingaritill."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 591bf0d..62c18f2 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sposta su"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sposta a sinistra"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sposta a destra"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"L\'app potrebbe non funzionare con la modalità multi-finestra"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tocca due volte per modificare."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Tocca due volte per aggiungere."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Positione <xliff:g id="POSITION">%1$d</xliff:g>. Tocca due volte per selezionare."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Sposta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Rimuovi <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato aggiunto alla posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato rimosso"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Il riquadro <xliff:g id="TILE_NAME">%1$s</xliff:g> è stato spostato nella posizione <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor di impostazioni rapide."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 7e0122d..097b427 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -565,8 +565,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"בחירת לחצן מקלדת"</string>
     <string name="preview" msgid="9077832302472282938">"תצוגה מקדימה"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"גרור כדי להוסיף משבצות"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"גרור לכאן כדי להסיר"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ערוך"</string>
     <string name="tuner_time" msgid="6572217313285536011">"שעה"</string>
   <string-array name="clock_options">
@@ -586,4 +585,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"הזז שמאלה"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"הזז ימינה"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"ייתכן שהאפליקציה לא תפעל עם ריבוי חלונות"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. הקש פעמיים כדי לערוך."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. הקש פעמיים כדי להוסיף."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>. הקש פעמיים כדי לבחור."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"הזזת <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"הסרת <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> התווסף למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> הוסר"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> הועבר למיקום <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"עורך הגדרות מהירות."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 36c0e1a..61ff6d4 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左に移動"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右に移動"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"アプリはマルチウィンドウでは動作しないことがあります"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> の <xliff:g id="TILE_NAME">%2$s</xliff:g> を編集するにはダブルタップします。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を追加するにはダブルタップします。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に配置します。選択するにはダブルタップします。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を移動します"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を削除します"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> をポジション <xliff:g id="POSITION">%2$d</xliff:g> に追加しました"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> を削除しました"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> をポジション <xliff:g id="POSITION">%2$d</xliff:g> に移動しました"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"クイック設定エディタ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 0e6f335..26f2529 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"აირჩიეთ კლავიატურის ღილაკი"</string>
     <string name="preview" msgid="9077832302472282938">"გადახედვა"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ფილების დასამატებლად, გადაიტანეთ ჩავლებით"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ამოსაშლელად, ჩავლებით გადმოიტანეთ აქ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"რედაქტირება"</string>
     <string name="tuner_time" msgid="6572217313285536011">"დრო"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ზემოთ გადატანა"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"მარცხნივ გადატანა"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"მარჯვნივ გადატანა"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"აპმა შეიძლება არ იმუშაოს მრავალი ფანჯრის რეჟიმში"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. რედაქტირებისთვის, შეეხეთ ორმაგად."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. დასამატებლად, შეეხეთ ორმაგად."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>. ასარჩევად, შეეხეთ ორმაგად."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-ის გადატანა"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-ის წაშლა"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> დამატებულია პოზიციაზე <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ამოიშალა"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> გადატანილია პოზიციაზე <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"სწრაფი პარამეტრების რედაქტორი."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 0a06bdf..737041e 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -309,8 +309,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> қауіпсіз режимде өшіріледі."</string>
-    <!-- no translation found for recents_stack_action_button_label (6593727103310426253) -->
-    <skip />
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Барлығын тазалау"</string>
     <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бұл қолданба көп терезені қолдамайды"</string>
     <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Қолданба көп терезені қолдамайды"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
@@ -499,58 +498,32 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"Зарядтау кезінде Батарея үнемдегіш қол жетімді емес"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Батарея үнемдегіш"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Өнімділікті және фондық деректерді азайтады"</string>
-    <!-- no translation found for keyboard_key_button_template (6230056639734377300) -->
-    <skip />
-    <!-- no translation found for keyboard_key_home (2243500072071305073) -->
-    <skip />
-    <!-- no translation found for keyboard_key_back (2337450286042721351) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_up (5584144111755734686) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_down (7331518671788337815) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_left (1346446024676962251) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_right (3317323247127515341) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_center (2566737770049304658) -->
-    <skip />
-    <!-- no translation found for keyboard_key_tab (3871485650463164476) -->
-    <skip />
-    <!-- no translation found for keyboard_key_space (2499861316311153293) -->
-    <skip />
-    <!-- no translation found for keyboard_key_enter (5739632123216118137) -->
-    <skip />
-    <!-- no translation found for keyboard_key_backspace (1559580097512385854) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_play_pause (3861975717393887428) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_stop (2859963958595908962) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_next (1894394911630345607) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_previous (4256072387192967261) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_rewind (2654808213360820186) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_fast_forward (3849417047738200605) -->
-    <skip />
-    <!-- no translation found for keyboard_key_page_up (5654098530106845603) -->
-    <skip />
-    <!-- no translation found for keyboard_key_page_down (8720502083731906136) -->
-    <skip />
-    <!-- no translation found for keyboard_key_forward_del (1391451334716490176) -->
-    <skip />
-    <!-- no translation found for keyboard_key_move_home (2765693292069487486) -->
-    <skip />
-    <!-- no translation found for keyboard_key_move_end (5901174332047975247) -->
-    <skip />
-    <!-- no translation found for keyboard_key_insert (8530501581636082614) -->
-    <skip />
-    <!-- no translation found for keyboard_key_num_lock (5052537581246772117) -->
-    <skip />
-    <!-- no translation found for keyboard_key_numpad_template (8729216555174634026) -->
-    <skip />
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> түймесі"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"Артқа"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Жоғары"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Төмен"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Сол"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Оң"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Орталық"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Бос орын"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Ойнату/кідірту"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Тоқтату"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"Келесі"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Алдыңғы"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Кері айналдыру"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Алға айналдыру"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Сандық пернетақта <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Жүйе"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Негізгі бет"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Жақындағылар"</string>
@@ -610,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солға жылжыту"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңға жылжыту"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Қолданба көп тереземен жұмыс істемеуі мүмкін"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> орны, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Өңдеу үшін екі рет түртіңіз."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Қосу үшін екі рет түртіңіз."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> орны. Таңдау үшін екі рет түртіңіз."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жылжыту"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жою"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> орнына қосылды"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> жойылды"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> орнына жылжытылды"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Жылдам параметрлер өңдегіші."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 46b1435..1cec0b0 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ផ្លាស់ទីទៅឆ្វេង"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ផ្លាស់ទីទៅស្តាំ"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"កម្មវិធីអាចនឹងមិនដំណើរការជាមួយពហុវិនដូទេ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ទីតាំង <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>, ប៉ះពីរដងដើម្បីកែ"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>, ប៉ះពីរដងដើម្បីបន្ថែម"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ទីតាំង <xliff:g id="POSITION">%1$d</xliff:g>, ប៉ះពីរដងដើម្បីជ្រើស"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ផ្លាស់ទី <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"យក <xliff:g id="TILE_NAME">%1$s</xliff:g> ចេញ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ត្រូវបានបន្ថែមទៅទីតាំង <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ត្រូវបានយកចេញ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> បានផ្លាស់ទីទៅទីតាំង <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"កម្មវិធីកែការកំណត់រហ័ស"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index f26abdc..2eb6141 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"ಕೀಬೋರ್ಡ್ ಬಟನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="preview" msgid="9077832302472282938">"ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ಟೈಲ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ಸಂಪಾದಿಸು"</string>
     <string name="tuner_time" msgid="6572217313285536011">"ಸಮಯ"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"ಬಹು ವಿಂಡೋದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. ಸಂಪಾದಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ಸೇರಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>. ಆಯ್ಕೆಮಾಡಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ಸರಿಸಿ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಿ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ <xliff:g id="TILE_NAME">%1$s</xliff:g> ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ <xliff:g id="TILE_NAME">%1$s</xliff:g> ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳ ಸಂಪಾದಕ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5e28f0b..ae60d0e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"위로 이동"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"왼쪽으로 이동"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"오른쪽으로 이동"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"앱이 멀티 윈도우에서 작동하지 않을 수 있습니다."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"위치 <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. 수정하려면 두 번 탭하세요."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. 추가하려면 두 번 탭하세요."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"위치 <xliff:g id="POSITION">%1$d</xliff:g>. 선택하려면 두 번 탭하세요."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 이동"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 삭제"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일이 위치 <xliff:g id="POSITION">%2$d</xliff:g>에 추가됩니다."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일이 삭제되었습니다."</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 타일을 위치 <xliff:g id="POSITION">%2$d</xliff:g>(으)로 이동함"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"빠른 설정 편집기"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 9cd5f60..b035bbb 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -478,7 +478,7 @@
     <string name="notification_importance_max" msgid="5806278962376556491">"Эскертмелер тизмесинин эң башында көрсөтүлүп, үн менен коштолуп, экранга чыгарылсын"</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>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> эскертмесин башкаруу каражаттары"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Түсү жана көрүнүшү"</string>
     <string name="night_mode" msgid="3540405868248625488">"Түнкү режим"</string>
     <string name="calibrate_display" msgid="5974642573432039217">"Дисплейди калибрлөө"</string>
@@ -505,7 +505,7 @@
     <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Төмөн"</string>
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Солго"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Оңго"</string>
-    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Экрандын ортосунда"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Ортолотуу"</string>
     <string name="keyboard_key_tab" msgid="3871485650463164476">"Өтмөк"</string>
     <string name="keyboard_key_space" msgid="2499861316311153293">"Боштук"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"Киргизүү"</string>
@@ -516,12 +516,12 @@
     <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Мурунку"</string>
     <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Артка түрүү"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Алдыга түрүү"</string>
-    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Бир бет жогору"</string>
-    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Бир бет төмөн"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
     <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Жок кылуу"</string>
     <string name="keyboard_key_move_home" msgid="2765693292069487486">"Башкы бет"</string>
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"Бүтүрүү"</string>
-    <string name="keyboard_key_insert" msgid="8530501581636082614">"Салуу"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
     <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Тутум"</string>
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Баскычтоптогу баскычты тандоо"</string>
     <string name="preview" msgid="9077832302472282938">"Алдын ала көрүү"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Керектүү нерселерди сүйрөп кошуңуз"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Убакыт"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Солго жылдыруу"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Оңго жылдыруу"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Көп терезе режиминде колдонмо иштебей калышы мүмкүн"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Түзөтүү үчүн эки жолу таптаңыз."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Кошуу үчүн эки жолу таптаңыз."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Орду - <xliff:g id="POSITION">%1$d</xliff:g>. Тандоо үчүн эки жолу таптаңыз."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дегенди жылдыруу"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> дегенди алып салуу"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> деген <xliff:g id="POSITION">%2$d</xliff:g>-орунга кошулду"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> алынып салынды"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> деген <xliff:g id="POSITION">%2$d</xliff:g>-орунга жылдырылды"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ыкчам жөндөөлөр түзөткүчү."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 182abe9..2355a84 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ເລື່ອນຊ້າຍ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ເລື່ອນຂວາ"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ກັບຫຼາຍໜ້າຈໍ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. ແຕະສອງເທື່ອເພື່ອແກ້ໄຂ."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ແຕະສອງເທື່ອເພື່ອເພີ່ມ."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>. ແຕະສອງເທື່ອເພື່ອເລືອກ."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ຍ້າຍ <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"ລຶບ <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ຖືກເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%2$d</xliff:g> ແລ້ວ"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"ລຶບ <xliff:g id="TILE_NAME">%1$s</xliff:g> ອອກແລ້ວ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ຍ້າຍໄປຕຳແໜ່ງ <xliff:g id="POSITION">%2$d</xliff:g> ແລ້ວ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f3b6842..93c0b69 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -584,6 +584,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Perkelti aukštyn"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Perkelti kairėn"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Perkelti dešinėn"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Naudojant kelių langų funkciją programa gali neveikti"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis, išklotinės elementas „<xliff:g id="TILE_NAME">%2$s</xliff:g>“. Dukart palieskite, kad redaguotumėte."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“. Dukart palieskite, kad pridėtumėte."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> padėtis. Dukart palieskite, kad pasirinktumėte."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Perkelti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Pašalinti išklotinės elementą „<xliff:g id="TILE_NAME">%1$s</xliff:g>“"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pridėtas prie <xliff:g id="POSITION">%2$d</xliff:g> pozicijos"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ pašalintas"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Išklotinės elementas „<xliff:g id="TILE_NAME">%1$s</xliff:g>“ perkeltas į <xliff:g id="POSITION">%2$d</xliff:g> padėtį"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Sparčiųjų nustatymų redagavimo priemonė."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 8983cde..0ee306b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -583,6 +583,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pārvietot uz augšu"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pārvietot pa kreisi"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pārvietot pa labi"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Iespējams, lietotnē nedarbosies vairāku logu režīms."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozīcija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Lai rediģētu, veiciet dubultskārienu."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lai pievienotu, veiciet dubultskārienu."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozīcija. Lai atlasītu, veiciet dubultskārienu."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Pārvietot elementu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Noņemt elementu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir pievienots <xliff:g id="POSITION">%2$d</xliff:g>. pozīcijā"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir noņemts"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Elements <xliff:g id="TILE_NAME">%1$s</xliff:g> ir pārvietots uz <xliff:g id="POSITION">%2$d</xliff:g>. pozīciju"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Ātro iestatījumu redaktors."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 954a9d0..cfacc43 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместете нагоре"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Преместете налево"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Преместете надесно"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Апликацијата може да не работи со повеќе прозорци"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Место <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Допрете двапати за уредување."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Допрете двапати за додавање."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Место <xliff:g id="POSITION">%1$d</xliff:g>. Допрете двапати за избирање."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Преместете <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Отстранете <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е додадена на место <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е отстранета"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> е преместена на место <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Уредник за брзи поставки."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 1149147..deca898 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"കീബോർഡ് ബട്ടൺ തിരഞ്ഞെടുക്കൂ"</string>
     <string name="preview" msgid="9077832302472282938">"പ്രിവ്യു നടത്തുക"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ടൈലുകൾ ചേർക്കുന്നതിന് വലിച്ചിടുക"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
     <string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
     <string name="tuner_time" msgid="6572217313285536011">"സമയം"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ഇടത്തേക്ക് നീക്കുക"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"വലത്തേക്ക് നീക്കുക"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"മൾട്ടി-വിൻഡോയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. എഡിറ്റുചെയ്യുന്നതിന് രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. ചേർക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>. തിരഞ്ഞെടുക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കുക"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കംചെയ്യുക"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"സ്ഥാനം <xliff:g id="POSITION">%2$d</xliff:g>-ലേക്ക് <xliff:g id="TILE_NAME">%1$s</xliff:g> ചേർക്കുന്നു"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കംചെയ്യുന്നു"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"സ്ഥാനം <xliff:g id="POSITION">%2$d</xliff:g>-ലേക്ക് <xliff:g id="TILE_NAME">%1$s</xliff:g> നീക്കി"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index bafb558..b701e21 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -581,4 +581,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Зүүн тийш зөөх"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Баруун тийш зөөх"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Олон цонхтой үед апп ажиллахгүй байж болзошгүй"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Байршил <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Засахын тулд 2 удаа дарна уу."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Нэмэхийн тулд 2 удаа дарна уу."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Албан тушаал <xliff:g id="POSITION">%1$d</xliff:g>. Сонгохын тулд 2 удаа дарна уу."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г зөөх"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г устгах"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г <xliff:g id="POSITION">%2$d</xliff:g> байршилд нэмсэн"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г устгасан"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g>-г <xliff:g id="POSITION">%2$d</xliff:g> байршилд зөөсөн"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Түргэн тохиргоо засварлагч."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 00d65cd..6c6e634 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"कीबोर्ड बटण निवडा"</string>
     <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइल जोडण्यासाठी ड्रॅग करा"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"काढण्यासाठी येथे ड्रॅग करा"</string>
     <string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
     <string name="tuner_time" msgid="6572217313285536011">"वेळ"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"वर हलवा"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"डावीकडे हलवा"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"उजवीकडे हलवा"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"एकाधिक-विंडो सह अॅप कार्य करू शकत नाही"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. संपादित करण्यासाठी दोनदा टॅप करा."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> . जोडण्यासाठी दोनदा टॅप करा."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिती <xliff:g id="POSITION">%1$d</xliff:g>. निवडण्यासाठी दोनदा टॅप करा."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> हलवा"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> काढा"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला <xliff:g id="POSITION">%2$d</xliff:g> स्थितीवर जोडले आहे"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला काढले आहे"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ला <xliff:g id="POSITION">%2$d</xliff:g> स्थितीवर हलविले"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"द्रुत सेटिंग्ज संपादक."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 68ce748..335ff4c 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Alih ke atas"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Alih ke kiri"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Alih ke kanan"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Apl mungkin tidak berfungsi dengan berbilang tetingkap"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dwiketik untuk mengedit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dwiketik untuk menambah."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>. Dwiketik untuk memilih."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Alihkan <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Alih keluar <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ditambahkan pada kedudukan <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dialih keluar"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> dialihkan ke kedudukan <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor tetapan pantas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 3cfc675..d309991 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -508,12 +508,12 @@
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"ဌာန"</string>
     <string name="keyboard_key_tab" msgid="3871485650463164476">"တဘ်"</string>
     <string name="keyboard_key_space" msgid="2499861316311153293">"နေရာခြားပါ"</string>
-    <string name="keyboard_key_enter" msgid="5739632123216118137">"ဝင်ပါ"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter ခလုတ်"</string>
     <string name="keyboard_key_backspace" msgid="1559580097512385854">"နောက်ပြန်ဖျက်ပါ"</string>
     <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"ဖွင့်ပါ/ခဏရပ်ပါ"</string>
     <string name="keyboard_key_media_stop" msgid="2859963958595908962">"ရပ်ပါ"</string>
     <string name="keyboard_key_media_next" msgid="1894394911630345607">"ရှေ့သို့"</string>
-    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"အနောက်သို့"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"ယခင်"</string>
     <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"နောက်သို့ရစ်ပါ"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"ရှေ့သို့ရစ်ပါ"</string>
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"အပေါ်စာမျက်နှာသို့သွားပါ"</string>
@@ -522,8 +522,8 @@
     <string name="keyboard_key_move_home" msgid="2765693292069487486">"ပင်မ"</string>
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"ပြီးပါပြီ"</string>
     <string name="keyboard_key_insert" msgid="8530501581636082614">"ထည့်ပါ"</string>
-    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"နံပါတ်လော့ခ်ချပါ"</string>
-    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"နံပါတ်ခလုတ်ခုံ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ဂဏန်းကွက်<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"စနစ်"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ဘယ်ဘက်သို့ရွှေ့ပါ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ညာဘက်သို့ရွှေ့ပါ"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"အက်ပ်သည် ဝင်းဒိုးများတပြိုင်နက်ဖွင့်ခြင်းကို မပံ့ပိုးပါ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>၊ <xliff:g id="TILE_NAME">%2$s</xliff:g> နေရာ။ တည်းဖြတ်ရန် နှစ်ချက်တို့ပါ။"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>။ ပေါင်းထည့်ရန် နှစ်ချက်တို့ပါ။"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g> နေရာ။ ရွေးချယ်ရန် နှစ်ချက်တို့ပါ။"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုရွှေ့ပါ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုဖယ်ရှားပါ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကို <xliff:g id="POSITION">%2$d</xliff:g> နေရာသို့ ပေါင်းထည့်ထားပါသည်"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကိုဖယ်ရှားလိုက်ပါပြီ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ကို <xliff:g id="POSITION">%2$d</xliff:g> နေရာသို့ ရွှေ့လိုက်ပါပြီ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 0a21abc..8a961fc 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytt mot venstre"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytt mot høyre"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerer kanskje ikke i Flervindusmodus"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Plassering <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dobbelttrykk for å endre."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dobbelttrykk for å legge til."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Plassering <xliff:g id="POSITION">%1$d</xliff:g>. Dobbelttrykk for å velge."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flytt <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Fjern <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er lagt til i plassering <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er fjernet"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> er flyttet til plassering <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsvindu for hurtiginnstillinger."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index d2d4e97..7e91a53 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"किबोर्ड बटन चयन गर्नुहोस्"</string>
     <string name="preview" msgid="9077832302472282938">"पूर्वावलोकन"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"टाइलहरू थप्न तान्नुहोस्"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
     <string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
     <string name="tuner_time" msgid="6572217313285536011">"समय"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"बाँया सार्नुहोस्"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"दायाँ सार्नुहोस्"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"अनुप्रयोगले बहु-विन्डोमा काम नगर्न सक्छ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। सम्पादन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। थप्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>। चयन गर्नका लागि डबल ट्याप गर्नुहोस्।"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई सार्नुहोस्"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई हटाउनुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई स्थिति <xliff:g id="POSITION">%2$d</xliff:g> मा थपियो"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई हटाइयो"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई स्थिति <xliff:g id="POSITION">%2$d</xliff:g> मा सारियो"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"द्रुत सेटिङ सम्पादक।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 42dea78..3cad1fa 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Omhoog"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Naar links"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Naar rechts"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"De app werkt mogelijk niet met meerdere vensters"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Positie <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dubbeltik om te bewerken."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dubbeltik om toe te voegen."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Positie <xliff:g id="POSITION">%1$d</xliff:g>. Dubbeltik om te selecteren."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verplaatsen"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> verwijderen"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is toegevoegd op positie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verwijderd"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> is verplaatst naar positie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor voor \'Snelle instellingen\'."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index b58b2c8..91baa9b 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"ਕੀ-ਬੋਰਡ ਬਟਨ ਚੁਣੋ"</string>
     <string name="preview" msgid="9077832302472282938">"ਝਲਕ"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ਟਾਇਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘਸੀਟੋ"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
     <string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="tuner_time" msgid="6572217313285536011">"ਸਮਾਂ"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ਉੱਪਰ ਲੈ ਜਾਓ"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ਖੱਬੇ ਲੈ ਜਾਓ"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ਸੱਜੇ ਲੈ ਜਾਓ"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਮਲਟੀ-ਵਿੰਡੋ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ਸਥਿਤੀ <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। ਸੰਪਾਦਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ਸਥਿਤੀ <xliff:g id="POSITION">%1$d</xliff:g>। ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ।"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ ਤਬਦੀਲ ਕਰੋ"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਹਟਾਓ"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="POSITION">%2$d</xliff:g> ਸਥਿਤੀ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ ਹਟਾਇਆ ਗਿਆ"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ਨੂੰ <xliff:g id="POSITION">%2$d</xliff:g> ਸਥਿਤੀ \'ਤੇ ਤਬਦੀਲ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index bb8f200..3aed4b2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -585,4 +585,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Przesuń w lewo"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Przesuń w prawo"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacja może nie działać w trybie wielu okien"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Położenie <xliff:g id="POSITION">%1$d</xliff:g>, kafelek <xliff:g id="TILE_NAME">%2$s</xliff:g>. Kliknij dwukrotnie, by edytować."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>. Kliknij dwukrotnie, by dodać."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Położenie <xliff:g id="POSITION">%1$d</xliff:g>. Kliknij dwukrotnie, by wybrać."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Przenieś kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Usuń kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> został dodany w położeniu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> został usunięty"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Kafelek <xliff:g id="TILE_NAME">%1$s</xliff:g> przeniesiony w położenie <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Edytor szybkich ustawień."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index dd9fbf0..055a2981 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"É possível que o app não funcione com várias janelas"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é removido"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configurações rápidas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a700215..f40c7c7 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"A aplicação pode não funcionar com multijanelas"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remover <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> removido"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de definições rápidas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index dd9fbf0..055a2981 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mover para a esquerda"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mover para a direita"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"É possível que o app não funcione com várias janelas"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posição <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Toque duas vezes para editar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Toque duas vezes para adicionar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posição <xliff:g id="POSITION">%1$d</xliff:g>. Toque duas vezes para selecionar."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Move <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Remove <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é adicionado à posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> é removido"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> movido para a posição <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor de configurações rápidas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 353f11c..a307698 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -583,6 +583,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mutați în sus"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Mutați spre stânga"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Mutați spre dreapta"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Este posibil ca aplicația să nu funcționeze cu ferestre multiple"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Atingeți de două ori pentru a edita."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Atingeți de două ori pentru a adăuga."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>. Atingeți de două ori pentru a selecta."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Mutați <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Eliminați <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> este adăugată pe poziția <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> este eliminată"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Caseta <xliff:g id="TILE_NAME">%1$s</xliff:g> a fost mutată pe poziția <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editorul pentru setări rapide."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 26d936a..5521664 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -480,7 +480,7 @@
     <string name="notification_importance_max" msgid="5806278962376556491">"Показывать со звуком в начале списка уведомлений и поверх всех окон"</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>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"Управление уведомлениями (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Цвета и стиль"</string>
     <string name="night_mode" msgid="3540405868248625488">"Ночной режим"</string>
     <string name="calibrate_display" msgid="5974642573432039217">"Калибровка дисплея"</string>
@@ -585,4 +585,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Сдвинуть влево"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Сдвинуть вправо"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Приложение не поддерживает многооконный режим"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>, кнопка \"<xliff:g id="TILE_NAME">%2$s</xliff:g>\". Чтобы изменить, нажмите дважды."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\". Чтобы добавить, нажмите дважды."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>. Чтобы выбрать, нажмите дважды."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Переместить кнопку \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Удалить кнопку \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\""</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" теперь занимает позицию <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" удалена"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Кнопка \"<xliff:g id="TILE_NAME">%1$s</xliff:g>\" теперь занимает позицию <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор быстрых настроек."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index b47af0d..61411d6 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"යතුරු පුවරු බොත්තම තෝරන්න"</string>
     <string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
     <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය කරන්න"</string>
     <string name="tuner_time" msgid="6572217313285536011">"වේලාව"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"වමට ගෙන යන්න"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"දකුණට ගෙන යන්න"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"යෙදුම බහු-කවුළුව සමඟ ක්‍රියා නොකළ හැකිය."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. වෙනස් කිරීමට දෙවරක් තට්ටු කරන්න."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. එක් කිරීමට දෙවරක් තට්ටු කරන්න."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>. තෝරා ගැනීමට දෙවරක් තට්ටු කරන්න."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ගෙන යන්න"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ඉවත් කරන්න"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> වන ස්ථානයට එක් කරන ලදි"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ඉවත් කරන ලදි"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g> වන ස්ථානයට ගෙන යන ලදි"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 6c3b477..f7967e3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -584,6 +584,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Posunúť nahor"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Posunúť doľava"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Posunúť doprava"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikácia nemusí fungovať v režime viacerých okien"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozícia <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Upravíte ju dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Pridáte ju dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozícia <xliff:g id="POSITION">%1$d</xliff:g>. Vyberiete ju dvojitým klepnutím."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Presunúť dlaždicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstrániť dlaždicu <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola pridaná na pozíciu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola odstránená"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Dlaždica <xliff:g id="TILE_NAME">%1$s</xliff:g> bola presunutá na pozíciu <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor rýchlych nastavení"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 359c909..f0b7bc7 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -508,7 +508,7 @@
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Levo"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Desno"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Sredina"</string>
-    <string name="keyboard_key_tab" msgid="3871485650463164476">"Zavihek"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulatorka"</string>
     <string name="keyboard_key_space" msgid="2499861316311153293">"Preslednica"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"Vnesi"</string>
     <string name="keyboard_key_backspace" msgid="1559580097512385854">"Premik nazaj"</string>
@@ -585,4 +585,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Premakni levo"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Premakni desno"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacija morda ne deluje v načinu z več okni"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Če želite urediti, se dvakrat dotaknite."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Če želite dodati, se dvakrat dotaknite."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Položaj: <xliff:g id="POSITION">%1$d</xliff:g>. Če želite izbrati, se dvakrat dotaknite."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Premik tega: <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Odstranitev tega: <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je dodano na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je odstranjeno"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> premaknjeno na položaj <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Urejevalnik hitrih nastavitev."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 2448a4a..893e471 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Lëviz majtas"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Lëviz djathtas"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Aplikacioni mund të mos punojë me funksionin me shumë dritare."</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Trokit dy herë për ta redaktuar."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Trokit dy herë për ta shtuar."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>. Trokit dy herë për ta zgjedhur."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Zhvendose <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Hiqe <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> është shtuar te pozicioni <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> u hoq"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> u zhvendos te pozicioni <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redaktori i cilësimeve të shpejta."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index a2a61db..6cfd7b0 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -583,6 +583,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Помери нагоре"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Помери улево"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Помери удесно"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Апликација можда неће функционисати са више прозора"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Двапут додирните да бисте изменили."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Двапут додирните да бисте додали."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција. Двапут додирните да бисте изабрали."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Премести плочицу <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Уклони плочицу <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је додата на <xliff:g id="POSITION">%2$d</xliff:g>. позицију"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је уклоњена"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Плочица <xliff:g id="TILE_NAME">%1$s</xliff:g> је премештена на <xliff:g id="POSITION">%2$d</xliff:g>. позицију"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Уређивач за Брза подешавања."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a78841c..6b1e949 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Flytta åt vänster"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Flytta åt höger"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Appen fungerar eventuellt inte i flerfönsterläge"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Position <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Tryck snabbt två gånger om du vill redigera positionen."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Lägg till genom att trycka snabbt två gånger."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Position <xliff:g id="POSITION">%1$d</xliff:g>. Välj den genom att trycka snabbt två gånger."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Flytta <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ta bort <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har lagts till på position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har tagits bort"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> har flyttats till position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigerare för snabbinställningar."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 7351edc..5acf6c0 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -499,17 +499,17 @@
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Kiokoa Betri"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Hupunguza data ya chini chini na utendaji"</string>
     <string name="keyboard_key_button_template" msgid="6230056639734377300">"Kitufe cha <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Mwanzo"</string>
     <string name="keyboard_key_back" msgid="2337450286042721351">"Nyuma"</string>
     <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"Juu"</string>
     <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"Chini"</string>
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Kushoto"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Kulia"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Katikati"</string>
-    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
-    <string name="keyboard_key_space" msgid="2499861316311153293">"Space"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Sogeza"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Nafasi"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
-    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Backspace"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"Nafasinyuma"</string>
     <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Cheza/Sitisha"</string>
     <string name="keyboard_key_media_stop" msgid="2859963958595908962">"Simamisha"</string>
     <string name="keyboard_key_media_next" msgid="1894394911630345607">"Inayofuata"</string>
@@ -518,10 +518,10 @@
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Sogeza mbele Haraka"</string>
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
-    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Delete"</string>
-    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
-    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
-    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"Futa"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Mwanzo"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"Mwisho"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Ingiza"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
     <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Mfumo"</string>
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sogeza juu"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sogeza kushoto"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sogeza kulia"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Huenda programu isifanye kazi kwenye madirisha mengi"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Gonga mara mbili ili ubadilishe."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Gonga mara mbili ili uongeze."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>. Gonga mara mbili ili uchague."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Hamisha <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Ondoa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imeongezwa kwenye nafasi ya <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imeondolewa"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> imehamishiwa kwenye nafasi ya <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Kihariri cha Mipangilio ya haraka."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index cfa587b..1c2f0de 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"மேலே நகர்த்து"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"இடப்புறம் நகர்த்து"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"வலப்புறம் நகர்த்து"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"பல சாளர அம்சத்தில் பயன்பாடு வேலைசெய்யாமல் போகக்கூடும்"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"நிலை <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. திருத்த, இருமுறை தட்டவும்."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. சேர்க்க, இருமுறை தட்டவும்."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"நிலை <xliff:g id="POSITION">%1$d</xliff:g>. தேர்ந்தெடுக்க, இருமுறை தட்டவும்."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ஐ நகர்த்தவும்"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ஐ அகற்றவும்"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> நிலை <xliff:g id="POSITION">%2$d</xliff:g> இல் சேர்க்கப்பட்டது"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> அகற்றப்பட்டது"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> நிலை <xliff:g id="POSITION">%2$d</xliff:g>க்கு நகர்த்தப்பட்டது"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"விரைவு அமைப்புகள் திருத்தி."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index b04d074..bbefad2 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ఎడమవైపుకు తరలించు"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"కుడివైపుకు తరలించు"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"అనువర్తనం బహుళ విండోల రూపంలో పని చేయకపోవచ్చు"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. సవరించడానికి రెండుసార్లు నొక్కండి."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. జోడించడానికి రెండుసార్లు నొక్కండి."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>. ఎంచుకోవడానికి రెండుసార్లు నొక్కండి."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తరలిస్తుంది"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g>ని తీసివేస్తుంది"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> స్థానం <xliff:g id="POSITION">%2$d</xliff:g>కి జోడించబడింది"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> తీసివేయబడింది"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> స్థానం <xliff:g id="POSITION">%2$d</xliff:g>కి తరలించబడింది"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"శీఘ్ర సెట్టింగ్‌ల ఎడిటర్."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 31e7634..809d425 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"เลือกปุ่มแป้นพิมพ์"</string>
     <string name="preview" msgid="9077832302472282938">"ดูตัวอย่าง"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"ลากเพื่อเพิ่มชิ้นส่วน"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"ลากมาที่นี่เพื่อนำออก"</string>
     <string name="qs_edit" msgid="2232596095725105230">"แก้ไข"</string>
     <string name="tuner_time" msgid="6572217313285536011">"เวลา"</string>
   <string-array name="clock_options">
@@ -584,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"เลื่อนไปทางซ้าย"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"เลื่อนไปทางขวา"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"แอปอาจทำงานกับหลายหน้าต่างไม่ได้"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g> <xliff:g id="TILE_NAME">%2$s</xliff:g> แตะ 2 ครั้งเพื่อแก้ไข"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> แตะ 2 ครั้งเพื่อเพิ่ม"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g> แตะ 2 ครั้งเพื่อเลือก"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"ย้าย <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"นำ <xliff:g id="TILE_NAME">%1$s</xliff:g> ออก"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"เพิ่ม <xliff:g id="TILE_NAME">%1$s</xliff:g> ลงในตำแหน่ง <xliff:g id="POSITION">%2$d</xliff:g> แล้ว"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"นำ <xliff:g id="TILE_NAME">%1$s</xliff:g> ออกแล้ว"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"ย้าย <xliff:g id="TILE_NAME">%1$s</xliff:g> ไปยังตำแหน่ง <xliff:g id="POSITION">%2$d</xliff:g> แล้ว"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"ตัวแก้ไขการตั้งค่าด่วน"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c144b9b..7e6ff8a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Ilipat pakaliwa"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Ilipat pakanan"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Maaaring hindi gumana ang app sa maraming window"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. I-double tap upang i-edit."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. I-double tap upang idagdag."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>. I-double tap upang piliin."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Ilipat ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Alisin ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"Idinagdag ang <xliff:g id="TILE_NAME">%1$s</xliff:g> sa posisyon <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Inalis ang <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Inilipat ang <xliff:g id="TILE_NAME">%1$s</xliff:g> sa posisyon <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Editor ng Mga mabilisang setting."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 0b40840..05621a5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -523,7 +523,7 @@
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
     <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
-    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> Sayısal Tuş Takımı"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"<xliff:g id="NAME">%1$s</xliff:g> (Sayısal Tuş Takımında)"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Sistem"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Ana ekran"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Son çağrılar"</string>
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yukarı taşı"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Sola taşı"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Sağa taşı"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Uygulama birden fazla pencerede çalışmayabilir"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. konum, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Düzenlemek için iki kez hafifçe dokunun."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Eklemek için iki kez hafifçe dokunun."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. konum. Seçmek için iki kez hafifçe dokunun."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusunu taşı"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusunu kaldır"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kutusu <xliff:g id="POSITION">%2$d</xliff:g>. konuma eklendi"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> kaldırıldı"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> <xliff:g id="POSITION">%2$d</xliff:g>. konumuna taşındı"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Hızlı ayar düzenleyicisi."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index d6da864..ac79649 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -585,4 +585,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перемістити ліворуч"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перемістити праворуч"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Додаток може не працювати в багатовіконному режимі"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Двічі торкніться, щоб змінити."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Двічі торкніться, щоб додати."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>. Двічі торкніться, щоб вибрати."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Перемістити <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Видалити <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> додано на позицію <xliff:g id="POSITION">%2$d</xliff:g>."</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> видалено"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> переміщено на позицію <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Редактор швидких налаштувань."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index cc7b8d2..a4a664b 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -582,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"اوپر منتقل کریں"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"بائیں منتقل کریں"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"دائیں منتقل کریں"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"ایپ شاید ملٹی ونڈو کے ساتھ کام نہ کرے"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>، <xliff:g id="TILE_NAME">%2$s</xliff:g>۔ ترمیم کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>۔ شامل کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>۔ منتخب کرنے کیلئے دو بار تھپتھپائیں۔"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"<xliff:g id="TILE_NAME">%1$s</xliff:g> کو منتقل کریں"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹائیں"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> شامل ہو گیا ہے"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> ہٹا دیا گیا"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="POSITION">%2$d</xliff:g> پوزیشن پر <xliff:g id="TILE_NAME">%1$s</xliff:g> منتقل ہو گیا ہے"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"فوری ترتیبات ایڈیٹر۔"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index eb4f402..f5bcc3d 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -309,7 +309,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Xavfsiz rejimda <xliff:g id="APP">%s</xliff:g> ilovasi o‘chirib qo‘yildi."</string>
-    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Barchasini tozalash"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hammasini tozalash"</string>
     <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
     <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Bu ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
@@ -514,7 +514,7 @@
     <string name="keyboard_key_media_stop" msgid="2859963958595908962">"To‘xtatish"</string>
     <string name="keyboard_key_media_next" msgid="1894394911630345607">"Keyingi"</string>
     <string name="keyboard_key_media_previous" msgid="4256072387192967261">"Avvalgi"</string>
-    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Orqaga o‘tkazish"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"Orqaga qaytarish"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"Oldinga o‘tkazish"</string>
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="8720502083731906136">"Page Down"</string>
@@ -523,7 +523,7 @@
     <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
     <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
-    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Raqamli tugma: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Raqamli klaviatura (<xliff:g id="NAME">%1$s</xliff:g>)"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"Tizim"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Bosh ekran"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"So‘nggi ishlatilganlar"</string>
@@ -563,8 +563,7 @@
     <string name="select_keycode" msgid="7413765103381924584">"Klaviatura tugmasini tanlang"</string>
     <string name="preview" msgid="9077832302472282938">"Oldindan ko‘rish"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Fragmentlar qo‘shish uchun torting"</string>
-    <!-- no translation found for drag_to_remove_tiles (3361212377437088062) -->
-    <skip />
+    <string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga sudrang"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Vaqt"</string>
   <string-array name="clock_options">
@@ -583,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Tepaga siljitish"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Chapga siljitish"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"O‘ngga siljitish"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"Ilova ko‘p oynali rejimni qo‘llab-quvvatlamaydi"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>-joy, “<xliff:g id="TILE_NAME">%2$s</xliff:g>” tugmasi. Tahrirlash uchun ustiga ikki marta bosing."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi. Qo‘shish uchun ustiga ikki marta bosing."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>. Belgilash uchun ustiga ikki marta bosing."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasini ko‘chirish"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasini o‘chirish"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi endi <xliff:g id="POSITION">%2$d</xliff:g>-joyni egallamoqda"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi o‘chirildi"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"“<xliff:g id="TILE_NAME">%1$s</xliff:g>” tugmasi endi <xliff:g id="POSITION">%2$d</xliff:g>-joyni egallanmoqda"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Tezkor sozlamalar muharriri"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 94eb62f..ed3e8f3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Di chuyển sang trái"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Di chuyển sang phải"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Ứng dụng có thể không hoạt động với nhiều cửa sổ"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Nhấn đúp để chỉnh sửa."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Nhấn đúp để thêm."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>. Nhấn đúp để chọn."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Di chuyển <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Xóa <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được thêm vào vị trí <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được di chuyển"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> được di chuyển sang vị trí <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Trình chỉnh sửa cài đặt nhanh."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 614ae70..3b0c023 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -309,8 +309,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>已在安全模式下停用。"</string>
-    <!-- no translation found for recents_stack_action_button_label (6593727103310426253) -->
-    <skip />
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
     <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"此应用不支持多窗口模式"</string>
     <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"应用不支持多窗口模式"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
@@ -479,7 +478,7 @@
     <string name="notification_importance_max" msgid="5806278962376556491">"在通知列表顶部显示,同时在屏幕上短暂显示,并允许发出提示音"</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>
+    <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>通知设置"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"颜色和外观"</string>
     <string name="night_mode" msgid="3540405868248625488">"夜间模式"</string>
     <string name="calibrate_display" msgid="5974642573432039217">"校准显示画面"</string>
@@ -499,58 +498,32 @@
     <string name="battery_detail_charging_summary" msgid="1279095653533044008">"充电过程中无法使用节电助手"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"节电助手"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"降低性能并限制后台流量"</string>
-    <!-- no translation found for keyboard_key_button_template (6230056639734377300) -->
-    <skip />
-    <!-- no translation found for keyboard_key_home (2243500072071305073) -->
-    <skip />
-    <!-- no translation found for keyboard_key_back (2337450286042721351) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_up (5584144111755734686) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_down (7331518671788337815) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_left (1346446024676962251) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_right (3317323247127515341) -->
-    <skip />
-    <!-- no translation found for keyboard_key_dpad_center (2566737770049304658) -->
-    <skip />
-    <!-- no translation found for keyboard_key_tab (3871485650463164476) -->
-    <skip />
-    <!-- no translation found for keyboard_key_space (2499861316311153293) -->
-    <skip />
-    <!-- no translation found for keyboard_key_enter (5739632123216118137) -->
-    <skip />
-    <!-- no translation found for keyboard_key_backspace (1559580097512385854) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_play_pause (3861975717393887428) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_stop (2859963958595908962) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_next (1894394911630345607) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_previous (4256072387192967261) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_rewind (2654808213360820186) -->
-    <skip />
-    <!-- no translation found for keyboard_key_media_fast_forward (3849417047738200605) -->
-    <skip />
-    <!-- no translation found for keyboard_key_page_up (5654098530106845603) -->
-    <skip />
-    <!-- no translation found for keyboard_key_page_down (8720502083731906136) -->
-    <skip />
-    <!-- no translation found for keyboard_key_forward_del (1391451334716490176) -->
-    <skip />
-    <!-- no translation found for keyboard_key_move_home (2765693292069487486) -->
-    <skip />
-    <!-- no translation found for keyboard_key_move_end (5901174332047975247) -->
-    <skip />
-    <!-- no translation found for keyboard_key_insert (8530501581636082614) -->
-    <skip />
-    <!-- no translation found for keyboard_key_num_lock (5052537581246772117) -->
-    <skip />
-    <!-- no translation found for keyboard_key_numpad_template (8729216555174634026) -->
-    <skip />
+    <string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g>按钮"</string>
+    <string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
+    <string name="keyboard_key_back" msgid="2337450286042721351">"返回"</string>
+    <string name="keyboard_key_dpad_up" msgid="5584144111755734686">"向上"</string>
+    <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下"</string>
+    <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左"</string>
+    <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"中心"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"空格"</string>
+    <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="1559580097512385854">"退格"</string>
+    <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"播放/暂停"</string>
+    <string name="keyboard_key_media_stop" msgid="2859963958595908962">"停止"</string>
+    <string name="keyboard_key_media_next" msgid="1894394911630345607">"下一曲"</string>
+    <string name="keyboard_key_media_previous" msgid="4256072387192967261">"上一曲"</string>
+    <string name="keyboard_key_media_rewind" msgid="2654808213360820186">"快退"</string>
+    <string name="keyboard_key_media_fast_forward" msgid="3849417047738200605">"快进"</string>
+    <string name="keyboard_key_page_up" msgid="5654098530106845603">"向上翻页"</string>
+    <string name="keyboard_key_page_down" msgid="8720502083731906136">"向下翻页"</string>
+    <string name="keyboard_key_forward_del" msgid="1391451334716490176">"删除"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
+    <string name="keyboard_key_insert" msgid="8530501581636082614">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
+    <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"数字键盘 <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"系统"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"主屏幕"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"最近"</string>
@@ -609,6 +582,14 @@
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上移"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"左移"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"右移"</string>
-    <!-- no translation found for forced_resizable_info_text (7591061837558867999) -->
-    <skip />
+    <string name="forced_resizable_info_text" msgid="7591061837558867999">"应用可能无法在多窗口模式下正常运行"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。点按再次即可修改。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。点按两次即可添加。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。点按两次即可选择。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移动<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>添加到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已将<xliff:g id="TILE_NAME">%1$s</xliff:g>移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速设置编辑器。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f5cdcf8..dc4a6dd 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -505,7 +505,7 @@
     <string name="keyboard_key_dpad_down" msgid="7331518671788337815">"向下"</string>
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"向左"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"向右"</string>
-    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"箭咀中心"</string>
+    <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"箭咀中央"</string>
     <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
     <string name="keyboard_key_space" msgid="2499861316311153293">"空格"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"輸入 (Enter)"</string>
@@ -519,8 +519,8 @@
     <string name="keyboard_key_page_up" msgid="5654098530106845603">"上一頁"</string>
     <string name="keyboard_key_page_down" msgid="8720502083731906136">"下一頁"</string>
     <string name="keyboard_key_forward_del" msgid="1391451334716490176">"刪除"</string>
-    <string name="keyboard_key_move_home" msgid="2765693292069487486">"頁面頂端"</string>
-    <string name="keyboard_key_move_end" msgid="5901174332047975247">"頁面底端"</string>
+    <string name="keyboard_key_move_home" msgid="2765693292069487486">"Home"</string>
+    <string name="keyboard_key_move_end" msgid="5901174332047975247">"End"</string>
     <string name="keyboard_key_insert" msgid="8530501581636082614">"插入"</string>
     <string name="keyboard_key_num_lock" msgid="5052537581246772117">"數字鎖定"</string>
     <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"數字鍵盤 <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"應用程式可能無法在多重視窗下運作"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。輕按兩下即可編輯。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。輕按兩下即可新增。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。輕按兩下即可選取。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移動 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已新增至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已移除"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> 已移至位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速設定編輯工具。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fea3cc7..72ff27c8b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"向左移"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"向右移"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"應用程式可能無法在多視窗模式下運作"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"位置 <xliff:g id="POSITION">%1$d</xliff:g>,<xliff:g id="TILE_NAME">%2$s</xliff:g>。輕按兩下即可編輯。"</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>。輕按兩下即可新增。"</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"位置 <xliff:g id="POSITION">%1$d</xliff:g>。輕按兩下即可選取。"</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"移動 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"已將 <xliff:g id="TILE_NAME">%1$s</xliff:g> 新增到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"已移除 <xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"已將 <xliff:g id="TILE_NAME">%1$s</xliff:g> 移到位置 <xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"快速設定編輯器。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e94c687..2eb9681 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -583,4 +583,13 @@
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Iya kwesokunxele"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Iya kwesokudla"</string>
     <string name="forced_resizable_info_text" msgid="7591061837558867999">"Uhlelo lokusebenza kungenzeka lungasebenzi namawindi amaningi"</string>
+    <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Isimo esingu-<xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Thepha kabili ukuze uhlele."</string>
+    <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Thepha kabili ukuze ungeze."</string>
+    <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Isimo esingu-<xliff:g id="POSITION">%1$d</xliff:g>. Thepha kabili ukuze ukhethe."</string>
+    <string name="accessibility_qs_edit_move_tile" msgid="2461819993780159542">"Hambisa i-<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_remove_tile" msgid="7484493384665907197">"Susa i-<xliff:g id="TILE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="8050200862063548309">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> ingezwe kusimo esingu-<xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> isusiwe"</string>
+    <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"I-<xliff:g id="TILE_NAME">%1$s</xliff:g> ihanjiswe kusimo esingu-<xliff:g id="POSITION">%2$d</xliff:g>"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Isihleli sezilungiselelo ezisheshayo."</string>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index 953dd65..337513d 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -38,9 +38,6 @@
     <dimen name="recents_tv_unselected_item_z">6dp</dimen>
     <dimen name="recents_tv_selected_item_z_delta">10dp</dimen>
 
-    <!-- Extra space around the PIP and its outline in PIP onboarding activity  -->
-    <dimen name="tv_pip_bounds_space">3dp</dimen>
-
     <!-- Values for text on recents cards on tv -->
     <dimen name="recents_tv_title_text_size">12sp</dimen>
 
@@ -52,4 +49,10 @@
     <dimen name="recents_tv_dismiss_icon_bottom_margin">1dip</dimen>
     <dimen name="recents_tv_dismiss_text_size">12sp</dimen>
 
+    <!-- Values for PIP in recents -->
+    <dimen name="recents_tv_pip_controls_margin_top">10dp</dimen>
+
+    <!-- Extra space around the PIP and its outline in PIP onboarding activity  -->
+    <dimen name="tv_pip_bounds_space">3dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a523a41..a01066d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1388,6 +1388,31 @@
     <string name="keyboard_shortcut_group_system_recents">Recents</string>
     <!-- User visible title for the the keyboard shortcut that triggers the back action. -->
     <string name="keyboard_shortcut_group_system_back">Back</string>
+    <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+    <string name="keyboard_shortcut_group_system_notifications">Notifications</string>
+    <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+    <string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
+    <!-- User visible title for the the keyboard shortcut that switches input methods. -->
+    <string name="keyboard_shortcut_group_system_switch_input">Switch input method</string>
+
+    <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+    <string name="keyboard_shortcut_group_applications">Applications</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+    <string name="keyboard_shortcut_group_applications_assist">Assist</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
+    <string name="keyboard_shortcut_group_applications_browser">Browser</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+    <string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
+    <string name="keyboard_shortcut_group_applications_email">Email</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the instant messaging app. -->
+    <string name="keyboard_shortcut_group_applications_im">IM</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+    <string name="keyboard_shortcut_group_applications_music">Music</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
+    <string name="keyboard_shortcut_group_applications_youtube">YouTube</string>
+    <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+    <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
 
     <!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
     <string name="tuner_full_zen_title">Show with volume controls</string>
diff --git a/packages/SystemUI/res/xml/night_mode.xml b/packages/SystemUI/res/xml/night_mode.xml
index d5f5333..34af820 100644
--- a/packages/SystemUI/res/xml/night_mode.xml
+++ b/packages/SystemUI/res/xml/night_mode.xml
@@ -27,10 +27,6 @@
         android:title="@string/when_night_mode_on">
 
         <SwitchPreference
-            android:key="dark_theme"
-            android:title="@string/use_dark_theme" />
-
-        <SwitchPreference
             android:key="adjust_tint"
             android:title="@string/adjust_tint" />
 
@@ -40,8 +36,4 @@
 
     </PreferenceCategory>
 
-    <Preference
-        android:selectable="false"
-        android:summary="@string/night_mode_disclaimer" />
-
 </PreferenceScreen>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 0d75fdd..53c2233 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -27,9 +27,25 @@
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 
 /**
  * Class factory to provide customizable SystemUI components.
@@ -82,6 +98,20 @@
         return new NotificationIconAreaController(context, phoneStatusBar);
     }
 
+    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);
+    }
+
     public <T> T createInstance(Class<T> classType) {
         return null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 83736ad..de8eec4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -64,6 +64,7 @@
     private boolean mAllowFancy;
     private boolean mFullRows;
     private int mNumQuickTiles;
+    private float mLastPosition;
 
     public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
         mQsContainer = container;
@@ -117,7 +118,7 @@
         } else if (MOVE_FULL_ROWS.equals(key)) {
             mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
         } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
-            mNumQuickTiles = QuickQSPanel.getNumQuickTiles(mQsContainer.getContext());
+            mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext());
             clearAnimationState();
         }
         updateAnimators();
@@ -260,6 +261,7 @@
         if (mOnKeyguard) {
             return;
         }
+        mLastPosition = position;
         if (mOnFirstPage && mAllowFancy) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
@@ -300,7 +302,7 @@
     private void clearAnimationState() {
         final int N = mAllViews.size();
         mQuickQsPanel.setAlpha(0);
-        mQuickQsPanel.setVisibility(View.INVISIBLE);
+        mQuickQsPanel.setVisibility(View.VISIBLE);
         for (int i = 0; i < N; i++) {
             View v = mAllViews.get(i);
             v.setAlpha(1);
@@ -338,6 +340,7 @@
         @Override
         public void run() {
             updateAnimators();
+            setPosition(mLastPosition);
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 8777a91..3e32905 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -24,8 +24,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
@@ -85,8 +83,6 @@
     abstract protected void handleClick();
     abstract protected void handleUpdateState(TState state, Object arg);
 
-    private UserManager mUserManager;
-
     /**
      * Declare the category of this tile.
      *
@@ -99,7 +95,6 @@
         mHost = host;
         mContext = host.getContext();
         mHandler = new H(host.getLooper());
-        mUserManager = UserManager.get(mContext);
     }
 
     public String getTileSpec() {
@@ -290,11 +285,12 @@
     }
 
     protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
-        UserHandle user = UserHandle.of(ActivityManager.getCurrentUser());
-        if (mUserManager.hasUserRestriction(userRestriction, user)
-                && !mUserManager.hasBaseUserRestriction(userRestriction, user)) {
+        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                userRestriction, ActivityManager.getCurrentUser());
+        if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+                userRestriction, ActivityManager.getCurrentUser())) {
             state.disabledByPolicy = true;
-            state.enforcedAdmin = EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+            state.enforcedAdmin = admin;
         } else {
             state.disabledByPolicy = false;
             state.enforcedAdmin = null;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 98a1c23..57a1a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -37,7 +37,7 @@
     private final int mTileSpacingPx;
     private int mTilePaddingTopPx;
 
-    private TextView mLabel;
+    protected TextView mLabel;
     private ImageView mPadLock;
 
     public QSTileView(Context context, QSIconView icon) {
@@ -81,7 +81,7 @@
         FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
     }
 
-    private void createLabel() {
+    protected void createLabel() {
         final Resources res = mContext.getResources();
         View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
         mLabel = (TextView) view.findViewById(R.id.tile_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index ab90179..2ef3672 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -143,7 +143,7 @@
         }
     };
 
-    public static int getNumQuickTiles(Context context) {
+    public int getNumQuickTiles(Context context) {
         return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
new file mode 100644
index 0000000..e512f93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.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.qs.customize;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSIconView;
+import com.android.systemui.qs.QSTileView;
+import libcore.util.Objects;
+
+public class CustomizeTileView extends QSTileView {
+
+    private TextView mAppLabel;
+
+    public CustomizeTileView(Context context, QSIconView icon) {
+        super(context, icon);
+    }
+
+    @Override
+    protected void createLabel() {
+        super.createLabel();
+        View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+        mAppLabel = (TextView) view.findViewById(R.id.tile_label);
+        mAppLabel.setAlpha(.6f);
+        mAppLabel.setSingleLine(true);
+        addView(view);
+    }
+
+    public void setShowAppLabel(boolean showAppLabel) {
+        mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
+        mLabel.setSingleLine(showAppLabel);
+    }
+
+    public void setAppLabel(CharSequence label) {
+        if (!Objects.equal(label, mAppLabel.getText())) {
+            mAppLabel.setText(label);
+        }
+    }
+
+    public TextView getAppLabel() {
+        return mAppLabel;
+    }
+}
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 83ac45c..716185f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -125,6 +125,7 @@
             mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
             new TileQueryHelper(mContext, mHost).setListener(mTileAdapter);
             mNotifQsContainer.setCustomizerAnimating(true);
+            mNotifQsContainer.setCustomizerShowing(true);
         }
     }
 
@@ -137,6 +138,7 @@
             save();
             mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
             mNotifQsContainer.setCustomizerAnimating(true);
+            mNotifQsContainer.setCustomizerShowing(false);
         }
     }
 
@@ -175,6 +177,7 @@
             specs.add(tile.getTileSpec());
         }
         mTileAdapter.setTileSpecs(specs);
+        mRecyclerView.setAdapter(mTileAdapter);
     }
 
     private void save() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 4c13451..2ba4044 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,7 +41,6 @@
 import com.android.internal.logging.MetricsProto;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSIconView;
-import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.customize.TileAdapter.Holder;
 import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
 import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
@@ -61,6 +60,10 @@
     private static final int TYPE_TILE = 0;
     private static final int TYPE_EDIT = 1;
     private static final int TYPE_ACCESSIBLE_DROP = 2;
+    private static final int TYPE_DIVIDER = 4;
+
+    private static final long EDIT_ID = 10000;
+    private static final long DIVIDER_ID = 20000;
 
     private final Context mContext;
 
@@ -68,7 +71,8 @@
     private final List<TileInfo> mTiles = new ArrayList<>();
     private final ItemTouchHelper mItemTouchHelper;
     private final AccessibilityManager mAccessibilityManager;
-    private int mDividerIndex;
+    private int mEditIndex;
+    private int mTileDividerIndex;
     private boolean mNeedsFocus;
     private List<String> mCurrentSpecs;
     private List<TileInfo> mOtherTiles;
@@ -87,7 +91,8 @@
 
     @Override
     public long getItemId(int position) {
-        return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1;
+        return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
+                : position == mEditIndex ? EDIT_ID : DIVIDER_ID;
     }
 
     public ItemTouchHelper getItemTouchHelper() {
@@ -131,8 +136,19 @@
             }
         }
         mTiles.add(null);
+        for (int i = 0; i < mOtherTiles.size(); i++) {
+            final TileInfo tile = mOtherTiles.get(i);
+            if (tile.isSystem) {
+                mOtherTiles.remove(i--);
+                mTiles.add(tile);
+            }
+        }
+        if (mOtherTiles.size() != 0) {
+            mTileDividerIndex = mTiles.size();
+            mTiles.add(null);
+        }
         mTiles.addAll(mOtherTiles);
-        mDividerIndex = mTiles.indexOf(null);
+        mEditIndex = mTiles.indexOf(null);
         notifyDataSetChanged();
     }
 
@@ -147,9 +163,12 @@
 
     @Override
     public int getItemViewType(int position) {
-        if (mAccessibilityMoving && position == mDividerIndex - 1) {
+        if (mAccessibilityMoving && position == mEditIndex - 1) {
             return TYPE_ACCESSIBLE_DROP;
         }
+        if (position == mTileDividerIndex) {
+            return TYPE_DIVIDER;
+        }
         if (mTiles.get(position) == null) {
             return TYPE_EDIT;
         }
@@ -160,12 +179,15 @@
     public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
         final Context context = parent.getContext();
         LayoutInflater inflater = LayoutInflater.from(context);
+        if (viewType == TYPE_DIVIDER) {
+            return new Holder(inflater.inflate(R.layout.qs_customize_tile_divider, parent, false));
+        }
         if (viewType == TYPE_EDIT) {
             return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false));
         }
         FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
                 false);
-        frame.addView(new QSTileView(context, new QSIconView(context)));
+        frame.addView(new CustomizeTileView(context, new QSIconView(context)));
         return new Holder(frame);
     }
 
@@ -176,6 +198,9 @@
 
     @Override
     public void onBindViewHolder(final Holder holder, final int position) {
+        if (holder.getItemViewType() == TYPE_DIVIDER) {
+            return;
+        }
         if (holder.getItemViewType() == TYPE_EDIT) {
             ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
                     mCurrentDrag != null ? R.string.drag_to_remove_tiles
@@ -213,7 +238,7 @@
 
         TileInfo info = mTiles.get(position);
 
-        if (position > mDividerIndex) {
+        if (position > mEditIndex) {
             info.state.contentDescription = mContext.getString(
                     R.string.accessibility_qs_edit_add_tile_label, info.state.label);
         } else if (mAccessibilityMoving) {
@@ -224,9 +249,11 @@
                     R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
         }
         holder.mTileView.onStateChanged(info.state);
+        holder.mTileView.setAppLabel(info.appLabel);
+        holder.mTileView.setShowAppLabel(position > mTileDividerIndex);
 
         if (mAccessibilityManager.isTouchExplorationEnabled()) {
-            final boolean selectable = !mAccessibilityMoving || position < mDividerIndex;
+            final boolean selectable = !mAccessibilityMoving || position < mEditIndex;
             holder.mTileView.setClickable(selectable);
             holder.mTileView.setFocusable(selectable);
             holder.mTileView.setImportantForAccessibility(selectable
@@ -239,7 +266,7 @@
                         if (mAccessibilityMoving) {
                             selectPosition(position, v);
                         } else {
-                            if (position < mDividerIndex) {
+                            if (position < mEditIndex) {
                                 showAccessibilityDialog(position, v);
                             } else {
                                 startAccessibleDrag(position);
@@ -253,7 +280,7 @@
 
     private void selectPosition(int position, View v) {
         // Remove the placeholder.
-        mTiles.remove(mDividerIndex--);
+        mTiles.remove(mEditIndex--);
         mAccessibilityMoving = false;
         move(mAccessibilityFromIndex, position, v);
         notifyDataSetChanged();
@@ -272,7 +299,7 @@
                         if (which == 0) {
                             startAccessibleDrag(position);
                         } else {
-                            move(position, mDividerIndex, v);
+                            move(position, mEditIndex, v);
                         }
                     }
                 }).setNegativeButton(android.R.string.cancel, null)
@@ -287,7 +314,7 @@
         mNeedsFocus = true;
         mAccessibilityFromIndex = position;
         // Add placeholder for last slot.
-        mTiles.add(mDividerIndex++, null);
+        mTiles.add(mEditIndex++, null);
         notifyDataSetChanged();
     }
 
@@ -296,25 +323,38 @@
     }
 
     private boolean move(int from, int to, View v) {
-        if (to > mDividerIndex) {
-            if (from >= mDividerIndex) {
+        if (to >= mEditIndex) {
+            if (from >= mEditIndex) {
                 return false;
             }
+            // Sort tiles into system/non-system groups.
+            TileInfo tile = mTiles.get(from);
+            if (tile.isSystem) {
+                if (to > mTileDividerIndex) {
+                    to = mTileDividerIndex;
+                }
+            } else {
+                if (mTileDividerIndex == mTiles.size()) {
+                    mTiles.add(null);
+                }
+                if (to <= mTileDividerIndex) {
+                    to = mTileDividerIndex;
+                }
+            }
         }
         CharSequence fromLabel = mTiles.get(from).state.label;
         move(from, to, mTiles);
-        mDividerIndex = mTiles.indexOf(null);
-        notifyItemChanged(from);
-        notifyItemMoved(from, to);
+        notifyDataSetChanged();
+        updateDividerLocations();
         CharSequence announcement;
-        if (to >= mDividerIndex) {
+        if (to >= mEditIndex) {
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
                     strip(mTiles.get(to)));
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE,
                     from);
             announcement = mContext.getString(R.string.accessibility_qs_edit_tile_removed,
                     fromLabel);
-        } else if (from >= mDividerIndex) {
+        } else if (from >= mEditIndex) {
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC,
                     strip(mTiles.get(to)));
             MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD,
@@ -333,6 +373,25 @@
         return true;
     }
 
+    private void updateDividerLocations() {
+        // The first null is the edit tiles label, the second null is the tile divider.
+        // If there is no second null, then there are no non-system tiles.
+        mEditIndex = -1;
+        mTileDividerIndex = mTiles.size();
+        for (int i = 0; i < mTiles.size(); i++) {
+            if (mTiles.get(i) == null) {
+                if (mEditIndex == -1) {
+                    mEditIndex = i;
+                } else {
+                    mTileDividerIndex = i;
+                }
+            }
+        }
+        if (mTiles.get(mTiles.size() - 1) == null) {
+            mTiles.remove(mTiles.size() - 1);
+        }
+    }
+
     private String strip(TileInfo tileInfo) {
         String spec = tileInfo.spec;
         if (spec.startsWith(CustomTile.PREFIX)) {
@@ -348,12 +407,12 @@
     }
 
     public class Holder extends ViewHolder {
-        private QSTileView mTileView;
+        private CustomizeTileView mTileView;
 
         public Holder(View itemView) {
             super(itemView);
             if (itemView instanceof FrameLayout) {
-                mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+                mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
                 mTileView.setBackground(null);
                 mTileView.getIcon().disableAnimation();
             }
@@ -367,6 +426,9 @@
             mTileView.findViewById(R.id.tile_label).animate()
                     .setDuration(DRAG_LENGTH)
                     .alpha(0);
+            mTileView.getAppLabel().animate()
+                    .setDuration(DRAG_LENGTH)
+                    .alpha(0);
         }
 
         public void stopDrag() {
@@ -377,13 +439,17 @@
             mTileView.findViewById(R.id.tile_label).animate()
                     .setDuration(DRAG_LENGTH)
                     .alpha(1);
+            mTileView.getAppLabel().animate()
+                    .setDuration(DRAG_LENGTH)
+                    .alpha(.6f);
         }
     }
 
     private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() {
         @Override
         public int getSpanSize(int position) {
-            return getItemViewType(position) == TYPE_EDIT ? 3 : 1;
+            final int type = getItemViewType(position);
+            return type == TYPE_EDIT || type == TYPE_DIVIDER ? 3 : 1;
         }
     };
 
@@ -401,7 +467,7 @@
             for (int i = 0; i < childCount; i++) {
                 final View child = parent.getChildAt(i);
                 final ViewHolder holder = parent.getChildViewHolder(child);
-                if (holder.getAdapterPosition() < mDividerIndex) {
+                if (holder.getAdapterPosition() < mEditIndex) {
                     continue;
                 }
 
@@ -443,7 +509,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    notifyItemChanged(mDividerIndex);
+                    notifyItemChanged(mEditIndex);
                 }
             });
         }
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 bbc8856..d04a2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -31,6 +31,7 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DrawableIcon;
+import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
@@ -79,7 +80,7 @@
                     mainHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            addTile(spec, state);
+                            addTile(spec, null, state, true);
                             mListener.onTilesChanged(mTiles);
                         }
                     });
@@ -103,28 +104,33 @@
         mListener = listener;
     }
 
-    private void addTile(String spec, QSTile.State state) {
+    private void addTile(String spec, CharSequence appLabel, State state, boolean isSystem) {
         if (mSpecs.contains(spec)) {
             return;
         }
         TileInfo info = new TileInfo();
         info.state = state;
         info.spec = spec;
+        info.appLabel = appLabel;
+        info.isSystem = isSystem;
         mTiles.add(info);
         mSpecs.add(spec);
     }
 
-    private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
+    private void addTile(String spec, Drawable drawable, CharSequence label, CharSequence appLabel,
+            Context context) {
         QSTile.State state = new QSTile.State();
         state.label = label;
         state.contentDescription = label;
         state.icon = new DrawableIcon(drawable);
-        addTile(spec, state);
+        addTile(spec, appLabel, state, false);
     }
 
     public static class TileInfo {
         public String spec;
+        public CharSequence appLabel;
         public QSTile.State state;
+        public boolean isSystem;
     }
 
     private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
@@ -147,7 +153,8 @@
                     icon.setTint(mContext.getColor(android.R.color.white));
                 }
                 CharSequence label = info.serviceInfo.loadLabel(pm);
-                addTile(spec, icon, label != null ? label.toString() : "null", mContext);
+                final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
+                addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
             }
             return tiles;
         }
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 6ddd46e..2032783 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -21,6 +21,7 @@
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.Looper;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.RelativeSizeSpan;
@@ -44,7 +45,6 @@
 
 public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
 
-    private final BatteryMeterDrawable mDrawable;
     private final BatteryController mBatteryController;
     private final BatteryDetail mBatteryDetail = new BatteryDetail();
 
@@ -52,13 +52,11 @@
     private boolean mPowerSave;
     private boolean mCharging;
     private boolean mDetailShown;
+    private boolean mPluggedIn;
 
     public BatteryTile(Host host) {
         super(host);
         mBatteryController = host.getBatteryController();
-        mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
-                host.getContext().getColor(R.color.batterymeter_frame_color));
-        mDrawable.setBatteryController(mBatteryController);
     }
 
     @Override
@@ -79,10 +77,8 @@
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            mDrawable.startListening();
             mBatteryController.addStateChangedCallback(this);
         } else {
-            mDrawable.stopListening();
             mBatteryController.removeStateChangedCallback(this);
         }
     }
@@ -118,7 +114,12 @@
         state.icon = new Icon() {
             @Override
             public Drawable getDrawable(Context context) {
-                return mDrawable;
+                BatteryMeterDrawable drawable =
+                        new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
+                        context.getColor(R.color.batterymeter_frame_color));
+                drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
+                drawable.onPowerSaveChanged(mPowerSave);
+                return drawable;
             }
 
             @Override
@@ -133,6 +134,7 @@
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         mLevel = level;
+        mPluggedIn = pluggedIn;
         mCharging = charging;
         refreshState((Integer) level);
         if (mDetailShown) {
@@ -143,6 +145,7 @@
     @Override
     public void onPowerSaveChanged(boolean isPowerSave) {
         mPowerSave = isPowerSave;
+        refreshState(null);
         if (mDetailShown) {
             mBatteryDetail.postBindView();
         }
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 65154f2..c72bbf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -154,7 +154,7 @@
             state.label = removeDoubleQuotes(cb.enabledDesc);
             signalContentDescription = cb.wifiSignalContentDescription;
         } else if (wifiNotConnected) {
-            state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_full_0);
+            state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
             state.label = r.getString(R.string.quick_settings_wifi_label);
             signalContentDescription = r.getString(R.string.accessibility_no_wifi);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d7777d5..8060e07 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -344,7 +344,7 @@
 
         // Update the nav bar scrim, but defer the animation until the enter-window event
         boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
-        updateNavBarScrim(animateNavBarScrim, null);
+        mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null);
 
         // If this is a new instance relaunched by AM, without going through the normal mechanisms,
         // then we have to manually trigger the enter animation state
@@ -417,39 +417,43 @@
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
-        // Update the nav bar for the current orientation
-        updateNavBarScrim(false /* animateNavBarScrim */, AnimationProps.IMMEDIATE);
 
         // Notify of the config change
         int newOrientation = getResources().getConfiguration().orientation;
+        int numStackTasks = mRecentsView.getStack().getStackTaskCount();
         EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
-                (mLastOrientation != newOrientation)));
+                (mLastOrientation != newOrientation), numStackTasks > 0));
         mLastOrientation = newOrientation;
     }
 
     @Override
-    public void onMultiWindowChanged(boolean inMultiWindow) {
-        super.onMultiWindowChanged(inMultiWindow);
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
+        super.onMultiWindowModeChanged(isInMultiWindowMode);
+
+        // Reload the task stack completely
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+        loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+        loader.loadTasks(this, loadPlan, loadOpts);
+
+        TaskStack stack = loadPlan.getTaskStack();
+        int numStackTasks = stack.getStackTaskCount();
+
         EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
-                false /* fromOrientationChange */));
+                false /* fromOrientationChange */, numStackTasks > 0));
 
         if (mRecentsView != null) {
-            // Reload the task stack completely
-            RecentsConfiguration config = Recents.getConfiguration();
-            RecentsActivityLaunchState launchState = config.getLaunchState();
-            RecentsTaskLoader loader = Recents.getTaskLoader();
-            RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
-            loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
-
-            RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
-            loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
-            loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
-            loader.loadTasks(this, loadPlan, loadOpts);
-
-            mRecentsView.updateStack(loadPlan.getTaskStack());
+            mRecentsView.updateStack(stack);
         }
 
-        EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
+        EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
+                numStackTasks > 0));
     }
 
     @Override
@@ -729,18 +733,4 @@
         });
         return true;
     }
-
-    /**
-     * Updates the nav bar scrim.
-     */
-    private void updateNavBarScrim(boolean animateNavBarScrim, AnimationProps animation) {
-        // Animate the SystemUI scrims into view
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        int taskCount = mRecentsView.getStack().getTaskCount();
-        boolean hasNavBarScrim = (taskCount > 0) && !ssp.hasTransposedNavBar();
-        mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
-        if (animateNavBarScrim && animation != null) {
-            mScrimViews.animateNavBarScrimVisibility(true, animation);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 43d627d..4dae746 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -584,18 +584,24 @@
         Rect systemInsets = new Rect();
         ssp.getStableInsets(systemInsets);
         Rect windowRect = ssp.getWindowRect();
+        // When docked, the nav bar insets are consumed and the activity is measured without insets.
+        // However, the window bounds include the insets, so we need to subtract them here to make
+        // them identical.
+        if (ssp.hasDockedTask()) {
+            windowRect.bottom -= systemInsets.bottom;
+            systemInsets.bottom = 0;
+        }
         calculateWindowStableInsets(systemInsets, windowRect);
         windowRect.offsetTo(0, 0);
 
         TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
-        stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
-                mTaskStackBounds);
 
         // Rebind the header bar and draw it for the transition
-        Rect taskStackBounds = new Rect(mTaskStackBounds);
         stackLayout.setSystemInsets(systemInsets);
         if (stack != null) {
-            stackLayout.initialize(windowRect, taskStackBounds,
+            stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+                    mTaskStackBounds);
+            stackLayout.initialize(windowRect, mTaskStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
             mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
         }
@@ -794,6 +800,9 @@
             synchronized (mHeaderBarLock) {
                 int toHeaderWidth = (int) toTransform.rect.width();
                 int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+                if (toHeaderWidth <= 0 || toHeaderHeight <= 0) {
+                    return null;
+                }
                 boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
                 mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
                         (int) toTransform.rect.height());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index 8be9ca7..e3bc2a7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -25,9 +25,12 @@
 
     public final boolean fromMultiWindow;
     public final boolean fromOrientationChange;
+    public final boolean hasStackTasks;
 
-    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange) {
+    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+            boolean hasStackTasks) {
         this.fromMultiWindow = fromMultiWindow;
         this.fromOrientationChange = fromOrientationChange;
+        this.hasStackTasks = hasStackTasks;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
index 19245d9..cf2a68e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -24,8 +24,10 @@
 public class MultiWindowStateChangedEvent extends EventBus.Event {
 
     public final boolean inMultiWindow;
+    public final boolean hasStackTasks;
 
-    public MultiWindowStateChangedEvent(boolean inMultiWindow) {
+    public MultiWindowStateChangedEvent(boolean inMultiWindow, boolean hasStackTasks) {
         this.inMultiWindow = inMultiWindow;
+        this.hasStackTasks = hasStackTasks;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
index b85ddac..216be61 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
@@ -23,7 +23,7 @@
 /**
  * This event is sent when a user drags in/out of a drop target.
  */
-public class DragDropTargetChangedEvent extends EventBus.Event {
+public class DragDropTargetChangedEvent extends EventBus.AnimatedEvent {
 
     // The task that is currently being dragged
     public final Task task;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 134b90c..483f9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -15,8 +15,6 @@
  */
 package com.android.systemui.recents.tv;
 
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.Intent;
@@ -55,11 +53,12 @@
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.animations.FocusAnimationHolder;
 import com.android.systemui.recents.tv.views.RecentsTvView;
 import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.tv.pip.PipManager;
-import com.android.systemui.tv.pip.PipControlsView;
+import com.android.systemui.tv.pip.PipRecentsOverlayManager;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -80,15 +79,13 @@
     private boolean mIgnoreAltTabRelease;
 
     private RecentsTvView mRecentsView;
-    private PipControlsView mPipControlsView;
-    private View mPipShadeView;
-    private AnimatorSet mPipControlsViewFadeInAnimator;
-    private AnimatorSet mPipControlsViewFadeOutAnimator;
+    private FocusAnimationHolder mRecentsFocusAnimationHolder;
+    private View mPipView;
     private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
     private FinishRecentsRunnable mFinishLaunchHomeRunnable;
 
-    private PipManager mPipManager;
-    private PipManager.Listener mPipListener = new PipManager.Listener() {
+    private final PipManager mPipManager = PipManager.getInstance();
+    private final PipManager.Listener mPipListener = new PipManager.Listener() {
         @Override
         public void onPipEntered() {
             updatePipUI();
@@ -113,10 +110,38 @@
 
         @Override
         public void onPipResizeAboutToStart() { }
-
-        @Override
-        public void onMediaControllerChanged() { }
     };
+    private PipRecentsOverlayManager mPipRecentsOverlayManager;
+    private final PipRecentsOverlayManager.Callback mPipRecentsOverlayManagerCallback =
+            new PipRecentsOverlayManager.Callback() {
+                @Override
+                public void onClosed() {
+                    dismissRecentsToLaunchTargetTaskOrHome();
+                }
+
+                @Override
+                public void onBackPressed() {
+                    RecentsTvActivity.this.onBackPressed();
+                }
+
+                @Override
+                public void onRecentsFocused() {
+                    mRecentsView.requestFocus();
+                }
+            };
+    private final View.OnFocusChangeListener mPipViewFocusChangeListener =
+            new View.OnFocusChangeListener() {
+                @Override
+                public void onFocusChange(View v, boolean hasFocus) {
+                    if (hasFocus) {
+                        mRecentsFocusAnimationHolder.startFocusLoseAnimation();
+                        mPipRecentsOverlayManager.requestFocus(
+                                mTaskStackViewAdapter.getItemCount() > 0);
+                    } else {
+                        mRecentsFocusAnimationHolder.startFocusGainAnimation();
+                    }
+                }
+            };
 
     /**
      * A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -248,7 +273,7 @@
             finish();
             return;
         }
-        mPipManager = PipManager.getInstance();
+        mPipRecentsOverlayManager = PipManager.getInstance().getPipRecentsOverlayManager();
 
         // Register this activity with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -263,21 +288,19 @@
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-        mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
-        mPipControlsView.setListener(new PipControlsView.Listener() {
-            @Override
-            public void onClosed() {
-                dismissRecentsToLaunchTargetTaskOrHome();
-            }
-        });
-        mPipShadeView = findViewById(R.id.pip_shade);
+        mRecentsFocusAnimationHolder = new FocusAnimationHolder(mRecentsView);
 
-        mPipControlsViewFadeInAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
-                R.anim.tv_pip_controls_fade_in);
-        mPipControlsViewFadeInAnimator.setTarget(mPipControlsView);
-        mPipControlsViewFadeOutAnimator = (AnimatorSet) AnimatorInflater.loadAnimator(this,
-                R.anim.tv_pip_controls_fade_out);
-        mPipControlsViewFadeOutAnimator.setTarget(mPipControlsView);
+        mPipView = findViewById(R.id.pip);
+        // Place mPipView at the PIP bounds for fine tuned focus handling.
+        Rect pipBounds = mPipManager.getPipBounds();
+        LayoutParams lp = (LayoutParams) mPipView.getLayoutParams();
+        lp.width = pipBounds.width();
+        lp.height = pipBounds.height();
+        lp.leftMargin = pipBounds.left;
+        lp.topMargin = pipBounds.top;
+        mPipView.setLayoutParams(lp);
+
+        mPipRecentsOverlayManager.setCallback(mPipRecentsOverlayManagerCallback);
 
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -289,7 +312,6 @@
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
 
-        updatePipUI();
         mPipManager.addListener(mPipListener);
     }
 
@@ -321,9 +343,7 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
 
-        mPipManager.onRecentsStarted();
-        // Give focus to the recents row whenever its visible to an user.
-        mRecentsView.requestFocus();
+        updatePipUI();
     }
 
     @Override
@@ -333,10 +353,21 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mPipRecentsOverlayManager.onRecentsResumed();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mPipRecentsOverlayManager.onRecentsPaused();
+    }
+
+    @Override
     protected void onStop() {
         super.onStop();
 
-        mPipManager.onRecentsStopped();
         mIgnoreAltTabRelease = false;
         // Notify that recents is now hidden
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
@@ -480,25 +511,13 @@
 
     private void updatePipUI() {
         if (mPipManager.isPipShown()) {
-            mPipControlsView.setAlpha(0);
-            mPipControlsView.setVisibility(View.VISIBLE);
-            mPipShadeView.setVisibility(View.INVISIBLE);
-            mPipControlsView.setOnChildFocusChangeListener(new View.OnFocusChangeListener() {
-                @Override
-                public void onFocusChange(View v, boolean hasFocus) {
-                    mPipManager.onPipViewFocusChangedInRecents(hasFocus);
-                    if (hasFocus) {
-                        mPipControlsViewFadeInAnimator.start();
-                    } else {
-                        mPipControlsViewFadeOutAnimator.start();
-                    }
-                    mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
-                }
-            });
-            mPipShadeView.setVisibility(View.GONE);
+            mPipView.setVisibility(View.VISIBLE);
+            mPipView.setOnFocusChangeListener(mPipViewFocusChangeListener);
+            mPipView.requestFocus();
         } else {
-            mPipControlsView.setVisibility(View.GONE);
-            mPipShadeView.setVisibility(View.GONE);
+            mPipView.setVisibility(View.GONE);
+            mPipRecentsOverlayManager.removePipRecentsOverlayView();
+            mRecentsFocusAnimationHolder.reset();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
new file mode 100644
index 0000000..864540c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/FocusAnimationHolder.java
@@ -0,0 +1,63 @@
+/*
+ * 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.recents.tv.animations;
+
+import android.content.res.Resources;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+/**
+ * Collections of Recents row's animation depending on the PIP's focus.
+ */
+public class FocusAnimationHolder {
+    private final float DIM_ALPHA = 0.5f;
+
+    private View mRecentsRowView;
+    private int mCardYDelta;
+    private long mDuration;
+
+    public FocusAnimationHolder(View recentsRowView) {
+        mRecentsRowView = recentsRowView;
+
+        Resources res = recentsRowView.getResources();
+        mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+        mDuration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+    }
+
+    public void startFocusGainAnimation() {
+        mRecentsRowView.animate()
+                .setDuration(mDuration)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .alpha(1f)
+                .translationY(0);
+    }
+
+    public void startFocusLoseAnimation() {
+        mRecentsRowView.animate()
+                .setDuration(mDuration)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .alpha(DIM_ALPHA)
+                .translationY(mCardYDelta);
+    }
+
+    public void reset() {
+        mRecentsRowView.setTransitionAlpha(1f);
+        mRecentsRowView.setTranslationY(0);
+    }
+}
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 da2f721..e0d0486 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -59,7 +59,6 @@
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
-import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
@@ -344,10 +343,10 @@
 
         if (RecentsDebugFlags.Static.EnableStackActionButton) {
             // Measure the stack action button within the constraints of the space above the stack
-            Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
+            Rect buttonBounds = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
             measureChild(mStackActionButton,
-                    MeasureSpec.makeMeasureSpec(actionButtonRect.width(), MeasureSpec.AT_MOST),
-                    MeasureSpec.makeMeasureSpec(actionButtonRect.height(), MeasureSpec.AT_MOST));
+                    MeasureSpec.makeMeasureSpec(buttonBounds.width(), MeasureSpec.AT_MOST),
+                    MeasureSpec.makeMeasureSpec(buttonBounds.height(), MeasureSpec.AT_MOST));
         }
 
         setMeasuredDimension(width, height);
@@ -376,16 +375,9 @@
         if (RecentsDebugFlags.Static.EnableStackActionButton) {
             // Layout the stack action button such that its drawable is start-aligned with the
             // stack, vertically centered in the available space above the stack
-            Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
-            int buttonLeft = isLayoutRtl()
-                    ? actionButtonRect.right + mStackActionButton.getPaddingStart()
-                    - mStackActionButton.getMeasuredWidth()
-                    : actionButtonRect.left - mStackActionButton.getPaddingStart();
-            int buttonTop = actionButtonRect.top +
-                    (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
-            mStackActionButton.layout(buttonLeft, buttonTop,
-                    buttonLeft + mStackActionButton.getMeasuredWidth(),
-                    buttonTop + mStackActionButton.getMeasuredHeight());
+            Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+            mStackActionButton.layout(buttonBounds.left, buttonBounds.top, buttonBounds.right,
+                    buttonBounds.bottom);
         }
 
         if (mAwaitingFirstLayout) {
@@ -479,6 +471,17 @@
                     false /* isDefaultDockState */, -1, true /* animateAlpha */,
                     true /* animateBounds */);
         }
+        if (mStackActionButton != null) {
+            event.addPostAnimationCallback(new Runnable() {
+                @Override
+                public void run() {
+                    // Move the clear all button to its new position
+                    Rect buttonBounds = getStackActionButtonBoundsFromStackLayout();
+                    mStackActionButton.setLeftTopRightBottom(buttonBounds.left, buttonBounds.top,
+                            buttonBounds.right, buttonBounds.bottom);
+                }
+            });
+        }
     }
 
     public final void onBusEvent(final DragEndEvent event) {
@@ -726,13 +729,31 @@
      */
     private void animateBackgroundScrim(float alpha, int duration) {
         Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
-        int alphaInt = (int) (alpha * 255);
+        // Calculate the absolute alpha to animate from
+        int fromAlpha = (int) ((mBackgroundScrim.getAlpha() / (DEFAULT_SCRIM_ALPHA * 255)) * 255);
+        int toAlpha = (int) (alpha * 255);
         mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
-                mBackgroundScrim.getAlpha(), alphaInt);
+                fromAlpha, toAlpha);
         mBackgroundScrimAnimator.setDuration(duration);
-        mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
-                ? Interpolators.ALPHA_OUT
-                : Interpolators.ALPHA_IN);
+        mBackgroundScrimAnimator.setInterpolator(toAlpha > fromAlpha
+                ? Interpolators.ALPHA_IN
+                : Interpolators.ALPHA_OUT);
         mBackgroundScrimAnimator.start();
     }
+
+    /**
+     * @return the bounds of the stack action button.
+     */
+    private Rect getStackActionButtonBoundsFromStackLayout() {
+        Rect actionButtonRect = new Rect(mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect);
+        int left = isLayoutRtl()
+                ? actionButtonRect.left - mStackActionButton.getPaddingLeft()
+                : actionButtonRect.right + mStackActionButton.getPaddingRight()
+                        - mStackActionButton.getMeasuredWidth();
+        int top = actionButtonRect.top +
+                (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
+        actionButtonRect.set(left, top, left + mStackActionButton.getMeasuredWidth(),
+                top + mStackActionButton.getMeasuredHeight());
+        return actionButtonRect;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 13ad9a5..07a1d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -16,40 +16,58 @@
 
 package com.android.systemui.recents.views;
 
-import android.app.Activity;
 import android.content.Context;
 import android.view.View;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
 
-    Context mContext;
+    private static final int DEFAULT_ANIMATION_DURATION = 150;
 
-    View mNavBarScrimView;
+    private Context mContext;
 
-    boolean mHasNavBarScrim;
-    boolean mShouldAnimateNavBarScrim;
+    private View mNavBarScrimView;
 
-    int mNavBarScrimEnterDuration;
+    private boolean mHasNavBarScrim;
+    private boolean mShouldAnimateNavBarScrim;
 
-    public SystemBarScrimViews(Activity activity) {
+    private int mNavBarScrimEnterDuration;
+
+    public SystemBarScrimViews(RecentsActivity activity) {
         mContext = activity;
         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+        mNavBarScrimView.forceHasOverlappingRendering(false);
         mNavBarScrimEnterDuration = activity.getResources().getInteger(
                 R.integer.recents_nav_bar_scrim_enter_duration);
     }
 
     /**
+     * Updates the nav bar scrim.
+     */
+    public void updateNavBarScrim(boolean animateNavBarScrim, boolean hasStackTasks,
+            AnimationProps animation) {
+        prepareEnterRecentsAnimation(isNavBarScrimRequired(hasStackTasks), animateNavBarScrim);
+        if (animateNavBarScrim && animation != null) {
+            animateNavBarScrimVisibility(true, animation);
+        }
+    }
+
+    /**
      * Prepares the scrim views for animating when entering Recents. This will be called before
      * the first draw, unless we are updating the scrim on configuration change.
      */
-    public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
+    private void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
         mHasNavBarScrim = hasNavBarScrim;
         mShouldAnimateNavBarScrim = animateNavBarScrim;
 
@@ -60,7 +78,7 @@
     /**
      * Animates the nav bar scrim visibility.
      */
-    public void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
+    private void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
         int toY = 0;
         if (visible) {
             mNavBarScrimView.setVisibility(View.VISIBLE);
@@ -79,6 +97,14 @@
         }
     }
 
+    /**
+     * @return Whether to show the nav bar scrim.
+     */
+    private boolean isNavBarScrimRequired(boolean hasStackTasks) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        return hasStackTasks && !ssp.hasTransposedNavBar() && !ssp.hasDockedTask();
+    }
+
     /**** EventBus events ****/
 
     /**
@@ -101,21 +127,48 @@
      */
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         if (mHasNavBarScrim) {
-            AnimationProps animation = new AnimationProps()
-                    .setDuration(AnimationProps.BOUNDS,
-                            TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
-                    .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+            AnimationProps animation = createBoundsAnimation(
+                    TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
             animateNavBarScrimVisibility(false, animation);
         }
     }
 
     public final void onBusEvent(DismissAllTaskViewsEvent event) {
         if (mHasNavBarScrim) {
-            AnimationProps animation = new AnimationProps()
-                    .setDuration(AnimationProps.BOUNDS,
-                            TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
-                    .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+            AnimationProps animation = createBoundsAnimation(
+                    TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION);
             animateNavBarScrimVisibility(false, animation);
         }
     }
+
+    public final void onBusEvent(ConfigurationChangedEvent event) {
+        animateScrimToCurrentNavBarState(event.hasStackTasks);
+    }
+
+    public final void onBusEvent(MultiWindowStateChangedEvent event) {
+        animateScrimToCurrentNavBarState(event.hasStackTasks);
+    }
+
+    /**
+     * Animates the scrim to match the state of the current nav bar.
+     */
+    private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+        boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
+        if (mHasNavBarScrim != hasNavBarScrim) {
+            AnimationProps animation = hasNavBarScrim
+                    ? createBoundsAnimation(DEFAULT_ANIMATION_DURATION)
+                    : AnimationProps.IMMEDIATE;
+            animateNavBarScrimVisibility(hasNavBarScrim, animation);
+        }
+        mHasNavBarScrim = hasNavBarScrim;
+    }
+
+    /**
+     * @return a default animation to aniamte the bounds of the scrim.
+     */
+    private AnimationProps createBoundsAnimation(int duration) {
+        return new AnimationProps()
+                .setDuration(AnimationProps.BOUNDS, duration)
+                .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+    }
 }
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 2508304..9eab0f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -537,11 +537,13 @@
             } else {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
             }
+            mInitialNormX = null;
         } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
             // If there is one stack task, ignore the min/max/initial scroll positions
             mMinScrollP = 0;
             mMaxScrollP = 0;
             mInitialScrollP = 0;
+            mInitialNormX = null;
         } else {
             // Set the max scroll to be the point where the front most task is visible with the
             // stack bottom offset
@@ -803,8 +805,9 @@
     public TaskViewTransform getStackTransformScreenCoordinates(Task task, float stackScroll,
             TaskViewTransform transformOut, TaskViewTransform frontTransform) {
         Rect windowRect = Recents.getSystemServices().getWindowRect();
-        TaskViewTransform transform = getStackTransform(task, stackScroll, transformOut,
-                frontTransform);
+        TaskViewTransform transform = getStackTransform(task, stackScroll, mFocusState,
+                transformOut, frontTransform, true /* forceUpdate */,
+                false /* ignoreTaskOverrides */);
         transform.rect.offset(windowRect.left, windowRect.top);
         return transform;
     }
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 ddea4d9..a2f61c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -267,9 +267,9 @@
         lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
         lp.setMarginStart(mHeaderBarHeight);
-        lp.rightMargin = mMoveTaskButton != null
+        lp.setMarginEnd(mMoveTaskButton != null
                 ? 2 * mHeaderBarHeight
-                : mHeaderBarHeight;
+                : mHeaderBarHeight);
         title.setLayoutParams(lp);
         if (secondaryButton != null) {
             lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
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 3eeabc7..e5ac0d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -141,9 +141,9 @@
             return;
         }
 
+        int viewWidth = mTaskViewRect.width();
+        int viewHeight = mTaskViewRect.height();
         if (mBitmapShader != null) {
-            int viewWidth = mTaskViewRect.width();
-            int viewHeight = mTaskViewRect.height();
 
             // We are drawing the thumbnail in the same orientation, so just fit the width
             int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale);
@@ -180,6 +180,9 @@
 
                 canvas.restoreToCount(count);
             }
+        } else {
+            canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
+                    mBgFillPaint);
         }
     }
 
@@ -319,12 +322,12 @@
         mDisabledInSafeMode = disabledInSafeMode;
         if (t.thumbnail != null) {
             setThumbnail(t.thumbnail, thumbnailInfo);
-            if (t.colorBackground != 0) {
-                mBgFillPaint.setColor(t.colorBackground);
-            }
         } else {
             setThumbnail(null, null);
         }
+        if (t.colorBackground != 0) {
+            mBgFillPaint.setColor(t.colorBackground);
+        }
     }
 
     /** Unbinds the thumbnail view from the task */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1c5d28a..4ed6426 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -19,7 +19,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
 import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -127,6 +129,8 @@
             SystemProperties.getBoolean("debug.enable_remote_input", true);
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
             = SystemProperties.getBoolean("debug.child_notifs", true);
+    public static final boolean FORCE_REMOTE_INPUT_HISTORY =
+            SystemProperties.getBoolean("debug.force_remoteinput_history", false);
 
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -182,6 +186,13 @@
     protected boolean mVisible;
     protected ArraySet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new ArraySet<>();
 
+    /**
+     * Notifications with keys in this set are not actually around anymore. We kept them around
+     * when they were canceled in response to a remote input interaction. This allows us to show
+     * what you replied and allows you to continue typing into it.
+     */
+    protected ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
     // mScreenOnFromKeyguard && mVisible.
     private boolean mVisibleToUser;
 
@@ -338,7 +349,7 @@
                 }, afterKeyguardGone);
                 return true;
             } else {
-                return super.onClickHandler(view, pendingIntent, fillInIntent);
+                return superOnClickHandler(view, pendingIntent, fillInIntent);
             }
         }
 
@@ -375,7 +386,8 @@
 
         private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
-            return super.onClickHandler(view, pendingIntent, fillInIntent);
+            return super.onClickHandler(view, pendingIntent, fillInIntent,
+                    StackId.FULLSCREEN_WORKSPACE_STACK_ID);
         }
 
         private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -566,6 +578,7 @@
                     public void run() {
                         processForRemoteInput(sbn.getNotification());
                         String key = sbn.getKey();
+                        mKeysKeptForRemoteInput.remove(key);
                         boolean isUpdate = mNotificationData.get(key) != null;
                         // In case we don't allow child notifications, we ignore children of
                         // notifications that have a summary, since we're not going to show them
@@ -904,7 +917,7 @@
         }
     }
 
-    protected View bindVetoButtonClickListener(View row, StatusBarNotification n) {
+    protected View bindVetoButtonClickListener(View row, final StatusBarNotification n) {
         View vetoButton = row.findViewById(R.id.veto);
         final String _pkg = n.getPackageName();
         final String _tag = n.getTag();
@@ -917,6 +930,11 @@
                         mContext.getString(R.string.accessibility_notification_dismissed));
                 try {
                     mBarService.onNotificationClear(_pkg, _tag, _id, _userId);
+                    if (FORCE_REMOTE_INPUT_HISTORY
+                            && mKeysKeptForRemoteInput.contains(n.getKey())) {
+                        removeNotification(n.getKey(), null);
+                        mKeysKeptForRemoteInput.remove(n.getKey());
+                    }
 
                 } catch (RemoteException ex) {
                     // system process is dead if we're here.
@@ -975,7 +993,7 @@
                             }
                             TaskStackBuilder.create(mContext)
                                     .addNextIntentWithParentStack(intent)
-                                    .startActivities(null,
+                                    .startActivities(getActivityOptions(),
                                             new UserHandle(UserHandle.getUserId(appUid)));
                             overrideActivityPendingAppTransition(keyguardShowing);
                         } catch (RemoteException e) {
@@ -1725,7 +1743,7 @@
                         } catch (RemoteException e) {
                         }
                         try {
-                            intent.send();
+                            intent.send(null, 0, null, null, null, null, getActivityOptions());
                         } catch (PendingIntent.CanceledException e) {
                             // the stack trace isn't very helpful here.
                             // Just log the exception message.
@@ -1833,7 +1851,8 @@
                                     }
                                 }
                                 try {
-                                    intent.send();
+                                    intent.send(null, 0, null, null, null, null,
+                                            getActivityOptions());
                                 } catch (PendingIntent.CanceledException e) {
                                     // the stack trace isn't very helpful here.
                                     // Just log the exception message.
@@ -1909,6 +1928,14 @@
         }
     }
 
+    protected Bundle getActivityOptions() {
+        // Anything launched from the notification shade should always go into the
+        // fullscreen stack.
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+        return options.toBundle();
+    }
+
     protected void visibilityChanged(boolean visible) {
         if (mVisible != visible) {
             mVisible = visible;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 8fe60a0..2b365dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -245,7 +245,57 @@
                         systemGroup.addItem(new KeyboardShortcutInfo(
                                 mContext.getString(R.string.keyboard_shortcut_group_system_recents),
                                 KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_system_notifications),
+                                KeyEvent.KEYCODE_N, KeyEvent.META_META_ON));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_system_shortcuts_helper),
+                                KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_system_switch_input),
+                                KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON));
                         result.add(systemGroup);
+
+                        KeyboardShortcutGroup applicationGroup = new KeyboardShortcutGroup(
+                                mContext.getString(R.string.keyboard_shortcut_group_applications),
+                                true);
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_assist),
+                                KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_browser),
+                                KeyEvent.KEYCODE_B, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_contacts),
+                                KeyEvent.KEYCODE_C, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_email),
+                                KeyEvent.KEYCODE_E, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_im),
+                                KeyEvent.KEYCODE_T, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_music),
+                                KeyEvent.KEYCODE_P, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_youtube),
+                                KeyEvent.KEYCODE_Y, KeyEvent.META_META_ON));
+                        applicationGroup.addItem(new KeyboardShortcutInfo(
+                                mContext.getString(
+                                        R.string.keyboard_shortcut_group_applications_calendar),
+                                KeyEvent.KEYCODE_L, KeyEvent.META_META_ON));
+                        result.add(applicationGroup);
+
                         showKeyboardShortcutsDialog(result);
                     }
                 }, deviceId);
@@ -354,11 +404,15 @@
             return null;
         }
         String displayLabelString;
-        if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+        if (info.getBaseCharacter() > Character.MIN_VALUE) {
             displayLabelString = String.valueOf(info.getBaseCharacter());
         } else if (SPECIAL_CHARACTER_NAMES.get(info.getKeycode()) != null) {
             displayLabelString = SPECIAL_CHARACTER_NAMES.get(info.getKeycode());
         } else {
+            // Special case for shortcuts with no base key or keycode.
+            if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+                return shortcutKeys;
+            }
             // TODO: Have a generic map for when we don't have the device's.
             char displayLabel = mKeyCharacterMap == null
                     ? 0 : mKeyCharacterMap.getDisplayLabel(info.getKeycode());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index d7e47c2..5fea674 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -21,6 +21,8 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
+import android.util.ArraySet;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
@@ -29,7 +31,8 @@
  */
 public class RemoteInputController {
 
-    private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>();
+    private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
+    private final ArraySet<String> mSpinning = new ArraySet<>();
     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     private final HeadsUpManager mHeadsUpManager;
 
@@ -44,7 +47,7 @@
         boolean found = pruneWeakThenRemoveAndContains(
                 entry /* contains */, null /* remove */);
         if (!found) {
-            mRemoteInputs.add(new WeakReference<>(entry));
+            mOpen.add(new WeakReference<>(entry));
         }
 
         apply(entry);
@@ -58,6 +61,18 @@
         apply(entry);
     }
 
+    public void addSpinning(String key) {
+        mSpinning.add(key);
+    }
+
+    public void removeSpinning(String key) {
+        mSpinning.remove(key);
+    }
+
+    public boolean isSpinning(String key) {
+        return mSpinning.contains(key);
+    }
+
     private void apply(NotificationData.Entry entry) {
         mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
         boolean remoteInputActive = isRemoteInputActive();
@@ -79,7 +94,7 @@
      */
     public boolean isRemoteInputActive() {
         pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
-        return !mRemoteInputs.isEmpty();
+        return !mOpen.isEmpty();
     }
 
     /**
@@ -91,10 +106,10 @@
     private boolean pruneWeakThenRemoveAndContains(
             NotificationData.Entry contains, NotificationData.Entry remove) {
         boolean found = false;
-        for (int i = mRemoteInputs.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = mRemoteInputs.get(i).get();
+        for (int i = mOpen.size() - 1; i >= 0; i--) {
+            NotificationData.Entry item = mOpen.get(i).get();
             if (item == null || item == remove) {
-                mRemoteInputs.remove(i);
+                mOpen.remove(i);
             } else if (item == contains) {
                 found = true;
             }
@@ -108,7 +123,16 @@
         mCallbacks.add(callback);
     }
 
+    public void remoteInputSent(NotificationData.Entry entry) {
+        int N = mCallbacks.size();
+        for (int i = 0; i < N; i++) {
+            mCallbacks.get(i).onRemoteInputSent(entry);
+        }
+    }
+
     public interface Callback {
-        void onRemoteInputActive(boolean active);
+        default void onRemoteInputActive(boolean active) {}
+
+        default void onRemoteInputSent(NotificationData.Entry entry) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
index 04095e7..3fdc35c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
@@ -23,6 +23,7 @@
 public class ExpandableIndicator extends ImageView {
 
     private boolean mExpanded;
+    private boolean mIsDefaultDirection = true;
 
     public ExpandableIndicator(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -31,16 +32,14 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
-                : R.drawable.ic_volume_expand_animation;
+        final int res = getDrawableResourceId(mExpanded);
         setImageResource(res);
     }
 
     public void setExpanded(boolean expanded) {
         if (expanded == mExpanded) return;
         mExpanded = expanded;
-        final int res = mExpanded ? R.drawable.ic_volume_expand_animation
-                : R.drawable.ic_volume_collapse_animation;
+        final int res = getDrawableResourceId(!mExpanded);
         // workaround to reset drawable
         final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext()
                 .getDrawable(res).getConstantState().newDrawable();
@@ -48,4 +47,19 @@
         avd.forceAnimationOnUI();
         avd.start();
     }
+
+    /** Whether the icons are using the default direction or the opposite */
+    public void setDefaultDirection(boolean isDefaultDirection) {
+        mIsDefaultDirection = isDefaultDirection;
+    }
+
+    private int getDrawableResourceId(boolean expanded) {
+        if (mIsDefaultDirection) {
+            return expanded ? R.drawable.ic_volume_collapse_animation
+                    : R.drawable.ic_volume_expand_animation;
+        } else {
+            return expanded ? R.drawable.ic_volume_expand_animation
+                    : R.drawable.ic_volume_collapse_animation;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 65e7973..3812429 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -85,7 +85,7 @@
             // wallpaper.
             final int lockWallpaperUserId =
                     mSelectedUser != null ? mSelectedUser.getIdentifier() : mCurrentUserId;
-            ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
+            ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_LOCK,
                     new Bundle(), lockWallpaperUserId);
             if (fd != null) {
                 try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 960515b..35fb2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -35,6 +35,7 @@
 public class NotificationsQuickSettingsContainer extends FrameLayout
         implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
 
+
     private DensityContainer mQsContainer;
     private View mUserSwitcher;
     private View mStackScroller;
@@ -43,6 +44,9 @@
     private boolean mQsExpanded;
     private boolean mCustomizerAnimating;
 
+    private int mBottomPadding;
+    private int mStackScrollerMargin;
+
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -53,6 +57,7 @@
         mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
         mQsContainer.addInflateListener(this);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
+        mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
         ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
         userSwitcher.setOnInflateListener(this);
@@ -75,7 +80,8 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        setPadding(0, 0, 0, insets.getStableInsetBottom());
+        mBottomPadding = insets.getStableInsetBottom();
+        setPadding(0, 0, 0, mBottomPadding);
         return insets;
     }
 
@@ -141,4 +147,22 @@
             invalidate();
         }
     }
+
+    public void setCustomizerShowing(boolean isShowing) {
+        if (isShowing) {
+            // Clear out bottom paddings/margins so the qs customization can be full height.
+            setPadding(0, 0, 0, 0);
+            setBottomMargin(mStackScroller, 0);
+        } else {
+            setPadding(0, 0, 0, mBottomPadding);
+            setBottomMargin(mStackScroller, mStackScrollerMargin);
+        }
+
+    }
+
+    private void setBottomMargin(View v, int bottomMargin) {
+        LayoutParams params = (LayoutParams) v.getLayoutParams();
+        params.bottomMargin = bottomMargin;
+        v.setLayoutParams(params);
+    }
 }
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 bb77c5b..c563eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -21,7 +21,9 @@
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
 import android.app.IActivityManager;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -876,7 +878,7 @@
         DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
                 R.id.qs_density_container);
         if (container != null) {
-            final QSTileHost qsh = new QSTileHost(mContext, this,
+            final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, mHotspotController,
                     mCastController, mFlashlightController,
@@ -1110,6 +1112,18 @@
                 mStatusBarKeyguardViewManager);
         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
+
+        if (FORCE_REMOTE_INPUT_HISTORY) {
+            mRemoteInputController.addCallback(new RemoteInputController.Callback() {
+                @Override
+                public void onRemoteInputSent(Entry entry) {
+                    if (mKeysKeptForRemoteInput.contains(entry.key)) {
+                        removeNotification(entry.key, null);
+                    }
+                }
+            });
+        }
+
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
     }
@@ -1378,6 +1392,42 @@
             clearCurrentMediaNotification();
             updateMediaMetaData(true, true);
         }
+        if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
+            Entry entry = mNotificationData.get(key);
+            StatusBarNotification sbn = entry.notification;
+
+            Notification.Builder b = Notification.Builder
+                    .recoverBuilder(mContext, sbn.getNotification().clone());
+            CharSequence[] oldHistory = sbn.getNotification().extras
+                    .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+            CharSequence[] newHistory;
+            if (oldHistory == null) {
+                newHistory = new CharSequence[1];
+            } else {
+                newHistory = new CharSequence[oldHistory.length + 1];
+                for (int i = 0; i < oldHistory.length; i++) {
+                    newHistory[i + 1] = oldHistory[i];
+                }
+            }
+            newHistory[0] = String.valueOf(entry.remoteInputText);
+            b.setRemoteInputHistory(newHistory);
+
+            Notification newNotification = b.build();
+
+            // Undo any compatibility view inflation
+            newNotification.contentView = sbn.getNotification().contentView;
+            newNotification.bigContentView = sbn.getNotification().bigContentView;
+            newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
+
+            StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
+                    sbn.getOpPkg(),
+                    sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
+                    0, newNotification, sbn.getUser(), sbn.getPostTime());
+
+            updateNotification(newSbn, null);
+            mKeysKeptForRemoteInput.add(entry.key);
+            return;
+        }
         if (deferRemoval) {
             mLatestRankingMap = ranking;
             mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -3043,8 +3093,8 @@
                             null, mContext.getBasePackageName(),
                             intent,
                             intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                            null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
-                            UserHandle.CURRENT.getIdentifier());
+                            null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
+                            getActivityOptions(), UserHandle.CURRENT.getIdentifier());
                 } catch (RemoteException e) {
                     Log.w(TAG, "Unable to start activity", e);
                 }
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 5dcd393..82496ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -81,7 +81,7 @@
 import java.util.Map;
 
 /** Platform implementation of the quick settings tile host **/
-public final class QSTileHost implements QSTile.Host, Tunable {
+public class QSTileHost implements QSTile.Host, Tunable {
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -450,7 +450,7 @@
         }
     }
 
-    public static List<String> loadTileSpecs(Context context, String tileList) {
+    protected List<String> loadTileSpecs(Context context, String tileList) {
         final Resources res = context.getResources();
         final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
         if (tileList == null) {
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 b507903..f3aba4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -68,7 +68,7 @@
     private ViewGroup mDateTimeAlarmGroup;
     private TextView mEmergencyOnly;
 
-    private ExpandableIndicator mExpandIndicator;
+    protected ExpandableIndicator mExpandIndicator;
 
     private boolean mListening;
     private AlarmManager.AlarmClockInfo mNextAlarm;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 95f26d4..6a2ecf4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -654,7 +654,7 @@
         }
 
         @Override
-        public void onMultiWindowChanged() {
+        public void onMultiWindowModeChanged() {
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 1f4ef4a..557f166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -121,8 +121,11 @@
         mEditText.setEnabled(false);
         mSendButton.setVisibility(INVISIBLE);
         mProgressBar.setVisibility(VISIBLE);
+        mEntry.remoteInputText = mEditText.getText();
+        mController.addSpinning(mEntry.key);
         mController.removeRemoteInput(mEntry);
         mEditText.mShowImeOnInputConnection = false;
+        mController.remoteInputSent(mEntry);
 
         try {
             mPendingIntent.send(mContext, 0, fillInIntent);
@@ -177,6 +180,7 @@
             return;
         }
         mController.removeRemoteInput(mEntry);
+        mController.removeSpinning(mEntry.key);
     }
 
     public void setPendingIntent(PendingIntent pendingIntent) {
@@ -213,6 +217,7 @@
         mEditText.setEnabled(true);
         mSendButton.setVisibility(VISIBLE);
         mProgressBar.setVisibility(INVISIBLE);
+        mController.removeSpinning(mEntry.key);
         updateSendButton();
         onDefocus();
     }
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 84e785d..ab44b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -654,11 +654,12 @@
     }
 
     private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
-        UserHandle user = UserHandle.of(ActivityManager.getCurrentUser());
-        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, user)
-                && !mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_ADD_USER, user)) {
+        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
+        if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
             record.isDisabledByAdmin = true;
-            record.enforcedAdmin = EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+            record.enforcedAdmin = admin;
         } else {
             record.isDisabledByAdmin = false;
             record.enforcedAdmin = null;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
index 8c945f9..ae2856c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -43,7 +43,6 @@
     public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
 
     private static final CharSequence KEY_AUTO = "auto";
-    private static final CharSequence KEY_DARK_THEME = "dark_theme";
     private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
     private static final CharSequence KEY_ADJUST_BRIGHTNESS = "adjust_brightness";
 
@@ -51,7 +50,6 @@
 
     private NightModeController mNightModeController;
     private SwitchPreference mAutoSwitch;
-    private SwitchPreference mDarkTheme;
     private SwitchPreference mAdjustTint;
     private SwitchPreference mAdjustBrightness;
     private UiModeManager mUiModeManager;
@@ -79,8 +77,6 @@
         addPreferencesFromResource(R.xml.night_mode);
         mAutoSwitch = (SwitchPreference) findPreference(KEY_AUTO);
         mAutoSwitch.setOnPreferenceChangeListener(this);
-        mDarkTheme = (SwitchPreference) findPreference(KEY_DARK_THEME);
-        mDarkTheme.setOnPreferenceChangeListener(this);
         mAdjustTint = (SwitchPreference) findPreference(KEY_ADJUST_TINT);
         mAdjustTint.setOnPreferenceChangeListener(this);
         mAdjustBrightness = (SwitchPreference) findPreference(KEY_ADJUST_BRIGHTNESS);
@@ -111,7 +107,6 @@
         mNightModeController.addListener(this);
         TunerService.get(getContext()).addTunable(this, Secure.BRIGHTNESS_USE_TWILIGHT,
                 NightModeController.NIGHT_MODE_ADJUST_TINT);
-        mDarkTheme.setChecked(mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO);
         calculateDisabled();
     }
 
@@ -129,12 +124,6 @@
         if (mAutoSwitch == preference) {
             MetricsLogger.action(getContext(), MetricsEvent.ACTION_TUNER_NIGHT_MODE_AUTO, value);
             mNightModeController.setAuto(value);
-        } else if (mDarkTheme == preference) {
-            MetricsLogger.action(getContext(),
-                    MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_DARK_THEME, value);
-            mUiModeManager.setNightMode(value ? UiModeManager.MODE_NIGHT_AUTO
-                    : UiModeManager.MODE_NIGHT_NO);
-            postCalculateDisabled();
         } else if (mAdjustTint == preference) {
             MetricsLogger.action(getContext(),
                     MetricsEvent.ACTION_TUNER_NIGHT_MODE_ADJUST_TINT, value);
@@ -163,19 +152,15 @@
     }
 
     private void calculateDisabled() {
-        int enabledCount = (mDarkTheme.isChecked() ? 1 : 0)
-                + (mAdjustTint.isChecked() ? 1 : 0)
+        int enabledCount = (mAdjustTint.isChecked() ? 1 : 0)
                 + (mAdjustBrightness.isChecked() ? 1 : 0);
         if (enabledCount == 1) {
-            if (mDarkTheme.isChecked()) {
-                mDarkTheme.setEnabled(false);
-            } else if (mAdjustTint.isChecked()) {
+            if (mAdjustTint.isChecked()) {
                 mAdjustTint.setEnabled(false);
             } else {
                 mAdjustBrightness.setEnabled(false);
             }
         } else {
-            mDarkTheme.setEnabled(true);
             mAdjustTint.setEnabled(true);
             mAdjustBrightness.setEnabled(true);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
index 15ad1f1..3f87611 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -16,11 +16,12 @@
 
 package com.android.systemui.tv.pip;
 
-import android.app.Activity;
 import android.content.Context;
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
 import android.view.View;
+import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View.OnFocusChangeListener;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -40,28 +41,29 @@
 /**
  * A view containing PIP controls including fullscreen, close, and media controls.
  */
-public class PipControlsView extends LinearLayout implements PipManager.Listener {
+public class PipControlsView extends LinearLayout {
     /**
      * An interface to listen user action.
      */
-    public interface Listener {
+    public abstract static interface Listener {
         /**
          * Called when an user clicks close PIP button.
          */
-        void onClosed();
-    }
+        public abstract void onClosed();
+    };
 
-    private final PipManager mPipManager = PipManager.getInstance();
     private MediaController mMediaController;
-    private Listener mListener;
 
-    private View mFullButtonView;
-    private View mFullDescriptionView;
-    private View mPlayPauseView;
-    private ImageView mPlayPauseButtonImageView;
-    private TextView mPlayPauseDescriptionTextView;
-    private View mCloseButtonView;
-    private View mCloseDescriptionView;
+    final PipManager mPipManager = PipManager.getInstance();
+    Listener mListener;
+
+    View mFullButtonView;
+    View mFullDescriptionView;
+    View mPlayPauseView;
+    ImageView mPlayPauseButtonImageView;
+    TextView mPlayPauseDescriptionTextView;
+    View mCloseButtonView;
+    View mCloseDescriptionView;
 
     private boolean mHasFocus;
     private OnFocusChangeListener mOnChildFocusChangeListener;
@@ -73,6 +75,13 @@
         }
     };
 
+    private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+        @Override
+        public void onMediaControllerChanged() {
+            updateMediaController();
+        }
+    };
+
     public PipControlsView(Context context) {
         this(context, null, 0, 0);
     }
@@ -87,6 +96,12 @@
 
     public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        LayoutInflater inflater = (LayoutInflater) getContext()
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.tv_pip_controls, this);
+
+        setOrientation(LinearLayout.HORIZONTAL);
+        setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
     }
 
     @Override
@@ -161,13 +176,13 @@
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         updateMediaController();
-        mPipManager.addListener(this);
+        mPipManager.addMediaListener(mPipMediaListener);
     }
 
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mPipManager.removeListener(this);
+        mPipManager.removeMediaListener(mPipMediaListener);
         if (mMediaController != null) {
             mMediaController.unregisterCallback(mMediaControllerCallback);
         }
@@ -230,24 +245,4 @@
     public void setListener(Listener listener) {
         mListener = listener;
     }
-
-    @Override
-    public void onPipEntered() { }
-
-    @Override
-    public void onPipActivityClosed() { }
-
-    @Override
-    public void onShowPipMenu() { }
-
-    @Override
-    public void onMoveToFullscreen() { }
-
-    @Override
-    public void onMediaControllerChanged() {
-        updateMediaController();
-    }
-
-    @Override
-    public void onPipResizeAboutToStart() { }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 68e0883..b5c1f57 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -62,9 +62,27 @@
 
     private static final int MAX_RUNNING_TASKS_COUNT = 10;
 
+    /**
+     * State when there's no PIP.
+     */
     public static final int STATE_NO_PIP = 0;
+    /**
+     * State when PIP is shown with an overlay message on top of it.
+     * This is used as default PIP state.
+     */
     public static final int STATE_PIP_OVERLAY = 1;
+    /**
+     * State when PIP menu dialog is shown.
+     */
     public static final int STATE_PIP_MENU = 2;
+    /**
+     * State when PIP is shown in Recents.
+     */
+    public static final int STATE_PIP_RECENTS = 3;
+    /**
+     * State when PIP is shown in Recents and it's focused to allow an user to control.
+     */
+    public static final int STATE_PIP_RECENTS_FOCUSED = 4;
 
     private static final int TASK_ID_NO_PIP = -1;
     private static final int INVALID_RESOURCE_TYPE = -1;
@@ -90,11 +108,13 @@
     private int mSuspendPipResizingReason;
 
     private Context mContext;
+    private PipRecentsOverlayManager mPipRecentsOverlayManager;
     private IActivityManager mActivityManager;
     private MediaSessionManager mMediaSessionManager;
     private int mState = STATE_NO_PIP;
     private final Handler mHandler = new Handler();
     private List<Listener> mListeners = new ArrayList<>();
+    private List<MediaListener> mMediaListeners = new ArrayList<>();
     private Rect mCurrentPipBounds;
     private Rect mPipBounds;
     private Rect mMenuModePipBounds;
@@ -107,9 +127,6 @@
     private MediaController mPipMediaController;
     private boolean mOnboardingShown;
 
-    private boolean mIsRecentsShown;
-    private boolean mIsPipFocusedInRecent;
-
     private final Runnable mResizePinnedStackRunnable = new Runnable() {
         @Override
         public void run() {
@@ -178,6 +195,7 @@
         mOnboardingShown = Prefs.getBoolean(
                 mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
 
+        mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
         mMediaSessionManager =
                 (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
     }
@@ -231,7 +249,7 @@
     /**
      * Moves the PIPed activity to the fullscreen and closes PIP system UI.
      */
-    public void movePipToFullscreen() {
+    void movePipToFullscreen() {
         mState = STATE_NO_PIP;
         mPipTaskId = TASK_ID_NO_PIP;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -247,8 +265,11 @@
      */
     private void showPipOverlay() {
         if (DEBUG) Log.d(TAG, "showPipOverlay()");
-        mState = STATE_PIP_OVERLAY;
-        PipOverlayActivity.showPipOverlay(mContext);
+        Intent intent = new Intent(mContext, PipOverlayActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchStackId(PINNED_STACK_ID);
+        mContext.startActivity(intent, options.toBundle());
     }
 
     /**
@@ -279,8 +300,10 @@
      * Resize the Pip to the appropriate size for the input state.
      * @param state In Pip state also used to determine the new size for the Pip.
      */
-    public void resizePinnedStack(int state) {
+    void resizePinnedStack(int state) {
         if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+        boolean wasRecentsShown =
+                (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED);
         mState = state;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onPipResizeAboutToStart();
@@ -291,7 +314,6 @@
                             mSuspendPipResizingReason);
             return;
         }
-        int animationDurationMs = -1;
         switch (mState) {
             case STATE_NO_PIP:
                 mCurrentPipBounds = null;
@@ -300,25 +322,24 @@
                 mCurrentPipBounds = mMenuModePipBounds;
                 break;
             case STATE_PIP_OVERLAY:
-                if (mIsRecentsShown) {
-                    if (mCurrentPipBounds == mRecentsFocusedPipBounds
-                            || mCurrentPipBounds == mRecentsFocusedPipBounds) {
-                        animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
-                    }
-                    if (mIsPipFocusedInRecent) {
-                        mCurrentPipBounds = mRecentsFocusedPipBounds;
-                    } else {
-                        mCurrentPipBounds = mRecentsPipBounds;
-                    }
-                } else {
-                    mCurrentPipBounds = mPipBounds;
-                }
+                mCurrentPipBounds = mPipBounds;
+                break;
+            case STATE_PIP_RECENTS:
+                mCurrentPipBounds = mRecentsPipBounds;
+                break;
+            case STATE_PIP_RECENTS_FOCUSED:
+                mCurrentPipBounds = mRecentsFocusedPipBounds;
                 break;
             default:
                 mCurrentPipBounds = mPipBounds;
                 break;
         }
         try {
+            int animationDurationMs = -1;
+            if (wasRecentsShown
+                    && (mState == STATE_PIP_RECENTS || mState == STATE_PIP_RECENTS_FOCUSED)) {
+                animationDurationMs = mRecentsFocusChangedAnimationDurationMs;
+            }
             mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds,
                     true, true, true, animationDurationMs);
         } catch (RemoteException e) {
@@ -327,67 +348,18 @@
     }
 
     /**
-     * Returns the current PIP bound for activities to sync their UI with PIP.
+     * Returns the default PIP bound.
      */
     public Rect getPipBounds() {
-        return mCurrentPipBounds;
+        return mPipBounds;
     }
 
     /**
-     * Called when Recents is started.
-     * PIPed activity will be resized accordingly and overlay will show available buttons.
+     * Returns the focused PIP bound while Recents is shown.
+     * This is used to place PIP controls in Recents.
      */
-    public void onRecentsStarted() {
-        mIsRecentsShown = true;
-        mIsPipFocusedInRecent = false;
-        if (mState == STATE_NO_PIP) {
-            return;
-        }
-        resizePinnedStack(STATE_PIP_OVERLAY);
-    }
-
-    /**
-     * Called when Recents is stopped.
-     * PIPed activity will be resized accordingly and overlay will hide available buttons.
-     */
-    public void onRecentsStopped() {
-        mIsRecentsShown = false;
-        mIsPipFocusedInRecent = false;
-        if (mState == STATE_NO_PIP) {
-            return;
-        }
-        resizePinnedStack(STATE_PIP_OVERLAY);
-    }
-
-    /**
-     * Returns {@code true} if recents is shown.
-     */
-    boolean isRecentsShown() {
-        return mIsRecentsShown;
-    }
-
-    /**
-     * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
-     * is focused.
-     * This only resizes pinned stack so it looks like it's in Recents.
-     * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
-     */
-    public void onPipViewFocusChangedInRecents(boolean hasFocus) {
-        mIsPipFocusedInRecent = hasFocus;
-        if (mState != STATE_PIP_OVERLAY) {
-            Log.w(TAG, "There is no pinned stack to handle focus change.");
-            return;
-        }
-        resizePinnedStack(STATE_PIP_OVERLAY);
-    }
-
-    /**
-     * Returns {@code true} if the PIP view in
-     * {@link com.android.systemui.recents.tv.RecentsTvActivity} is focused in Recents.
-     * This API is valid only when {@link isRecentsShown()} returns {@code true}.
-     */
-    boolean isPipViewFocusdInRecents() {
-        return mIsPipFocusedInRecent;
+    public Rect getRecentsFocusedPipBounds() {
+        return mRecentsFocusedPipBounds;
     }
 
     /**
@@ -396,6 +368,10 @@
      */
     private void showPipMenu() {
         if (DEBUG) Log.d(TAG, "showPipMenu()");
+        if (mPipRecentsOverlayManager.isRecentsShown()) {
+            if (DEBUG) Log.d(TAG, "Ignore showing PIP menu");
+            return;
+        }
         mState = STATE_PIP_MENU;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             mListeners.get(i).onShowPipMenu();
@@ -405,14 +381,34 @@
         mContext.startActivity(intent);
     }
 
+    /**
+     * Adds a {@link Listener} to PipManager.
+     */
     public void addListener(Listener listener) {
         mListeners.add(listener);
     }
 
+    /**
+     * Removes a {@link Listener} from PipManager.
+     */
     public void removeListener(Listener listener) {
         mListeners.remove(listener);
     }
 
+    /**
+     * Adds a {@link MediaListener} to PipManager.
+     */
+    public void addMediaListener(MediaListener listener) {
+        mMediaListeners.add(listener);
+    }
+
+    /**
+     * Removes a {@link MediaListener} from PipManager.
+     */
+    public void removeMediaListener(MediaListener listener) {
+        mMediaListeners.remove(listener);
+    }
+
     private void launchPipOnboardingActivityIfNeeded() {
         if (DEBUG_FORCE_ONBOARDING || !mOnboardingShown) {
             mOnboardingShown = true;
@@ -485,8 +481,8 @@
         }
         if (mPipMediaController != mediaController) {
             mPipMediaController = mediaController;
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).onMediaControllerChanged();
+            for (int i = mMediaListeners.size() - 1; i >= 0; i--) {
+                mMediaListeners.get(i).onMediaControllerChanged();
             }
             if (mPipMediaController == null) {
                 mHandler.postDelayed(mClosePipRunnable,
@@ -530,7 +526,7 @@
         return PLAYBACK_STATE_UNAVAILABLE;
     }
 
-    TaskStackListener mTaskStackListener = new TaskStackListener() {
+    private TaskStackListener mTaskStackListener = new TaskStackListener() {
         @Override
         public void onTaskStackChanged() {
             if (mState != STATE_NO_PIP) {
@@ -582,10 +578,10 @@
             mMediaSessionManager.addOnActiveSessionsChangedListener(
                     mActiveMediaSessionListener, null);
             updateMediaController(mMediaSessionManager.getActiveSessions(null));
-            if (mIsRecentsShown) {
+            if (mPipRecentsOverlayManager.isRecentsShown()) {
                 // If an activity becomes PIPed again after the fullscreen, the Recents is shown
                 // behind so we need to resize the pinned stack and show the correct overlay.
-                resizePinnedStack(STATE_PIP_OVERLAY);
+                resizePinnedStack(STATE_PIP_RECENTS);
             }
             for (int i = mListeners.size() - 1; i >= 0; i--) {
                 mListeners.get(i).onPipEntered();
@@ -604,7 +600,18 @@
             if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
             switch (mState) {
                 case STATE_PIP_OVERLAY:
-                    showPipOverlay();
+                    if (!mPipRecentsOverlayManager.isRecentsShown()) {
+                        showPipOverlay();
+                        break;
+                    } else {
+                        // This happens only if an activity is PIPed after the Recents is shown.
+                        // See {@link PipRecentsOverlayManager.requestFocus} for more details.
+                        resizePinnedStack(mState);
+                        break;
+                    }
+                case STATE_PIP_RECENTS:
+                case STATE_PIP_RECENTS_FOCUSED:
+                    mPipRecentsOverlayManager.addPipRecentsOverlayView();
                     break;
                 case STATE_PIP_MENU:
                     showPipMenu();
@@ -621,7 +628,7 @@
          * Invoked when an activity is pinned and PIP manager is set corresponding information.
          * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
          * because there's no guarantee for the PIP manager be return relavent information
-         * correctly. (e.g. {@link isPipShown}, {@link getPipBounds})
+         * correctly. (e.g. {@link isPipShown}).
          */
         void onPipEntered();
         /** Invoked when a PIPed activity is closed. */
@@ -632,6 +639,12 @@
         void onMoveToFullscreen();
         /** Invoked when we are above to start resizing the Pip. */
         void onPipResizeAboutToStart();
+    }
+
+    /**
+     * A listener interface to receive change in PIP's media controller
+     */
+    public interface MediaListener {
         /** Invoked when the MediaController on PIPed activity is changed. */
         void onMediaControllerChanged();
     }
@@ -645,4 +658,11 @@
         }
         return sPipManager;
     }
+
+    /**
+     * Gets an instance of {@link PipRecentsOverlayManager}.
+     */
+    public PipRecentsOverlayManager getPipRecentsOverlayManager() {
+        return mPipRecentsOverlayManager;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index ea9275f..c54e73a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -20,12 +20,6 @@
 import android.os.Bundle;
 
 import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.recents.Recents;
-
-import static android.content.pm.PackageManager.FEATURE_LEANBACK;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 
 /**
  * Activity to show the PIP menu to control PIP.
@@ -36,7 +30,6 @@
     private final PipManager mPipManager = PipManager.getInstance();
 
     private PipControlsView mPipControlsView;
-    private boolean mPipMovedToFullscreen;
 
     @Override
     protected void onCreate(Bundle bundle) {
@@ -47,17 +40,10 @@
         mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
     }
 
-    private void restorePipAndFinish() {
-        if (!mPipMovedToFullscreen) {
-            mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
-        }
-        finish();
-    }
-
     @Override
     public void onPause() {
         super.onPause();
-        restorePipAndFinish();
+        finish();
     }
 
     @Override
@@ -69,11 +55,6 @@
     }
 
     @Override
-    public void onBackPressed() {
-        restorePipAndFinish();
-    }
-
-    @Override
     public void onPipEntered() { }
 
     @Override
@@ -86,31 +67,13 @@
 
     @Override
     public void onMoveToFullscreen() {
-        mPipMovedToFullscreen = true;
         finish();
     }
 
     @Override
-    public void onMediaControllerChanged() { }
-
-    @Override
     public void onPipResizeAboutToStart() {
         finish();
         mPipManager.suspendPipResizing(
                 PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
     }
-
-    @Override
-    public void finish() {
-        super.finish();
-        if (mPipManager.isRecentsShown() && !mPipMovedToFullscreen) {
-            SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
-            for (int i = services.length - 1; i >= 0; i--) {
-                if (services[i] instanceof Recents) {
-                    ((Recents) services[i]).showRecents(false, null);
-                    break;
-                }
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 79daf3d..86ceff4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -86,7 +86,4 @@
 
     @Override
     public void onPipResizeAboutToStart() { }
-
-    @Override
-    public void onMediaControllerChanged() { }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 12cb4cd..5472ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -35,14 +35,6 @@
 public class PipOverlayActivity extends Activity implements PipManager.Listener {
     private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 4000;
 
-    /**
-     * The single instance of PipOverlayActivity to prevent it from restarting.
-     * Note that {@link PipManager} moves the PIPed activity to fullscreen if the activity is
-     * restarted. It's because the activity may be started by the Launcher or an intent again,
-     * but we don't want do so for the PipOverlayActivity.
-     */
-    private static PipOverlayActivity sPipOverlayActivity;
-
     private final PipManager mPipManager = PipManager.getInstance();
     private final Handler mHandler = new Handler();
     private View mGuideOverlayView;
@@ -54,47 +46,17 @@
         }
     };
 
-    /**
-     * Launches the PIP overlay. This should be only called on the main thread.
-     */
-    public static void showPipOverlay(Context context) {
-        if (sPipOverlayActivity == null) {
-            Intent intent = new Intent(context, PipOverlayActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            final ActivityOptions options = ActivityOptions.makeBasic();
-            options.setLaunchStackId(PINNED_STACK_ID);
-            context.startActivity(intent, options.toBundle());
-        }
-    }
-
     @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
         setContentView(R.layout.tv_pip_overlay);
         mGuideOverlayView = findViewById(R.id.guide_overlay);
-        mGuideButtonsView = findViewById(R.id.guide_buttons);
-        mGuideButtonPlayPauseImageView = (ImageView) findViewById(R.id.guide_button_play_pause);
         mPipManager.addListener(this);
-
-        sPipOverlayActivity = this;
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-        // TODO: Implement animation for this
-        if (mPipManager.isRecentsShown()) {
-            mGuideOverlayView.setVisibility(View.GONE);
-            if (mPipManager.isPipViewFocusdInRecents()) {
-                mGuideButtonsView.setVisibility(View.GONE);
-            } else {
-                mGuideButtonsView.setVisibility(View.VISIBLE);
-                updateGuideButtonsView();
-            }
-        } else {
-            mGuideOverlayView.setVisibility(View.VISIBLE);
-            mGuideButtonsView.setVisibility(View.GONE);
-        }
         mHandler.removeCallbacks(mHideGuideOverlayRunnable);
         mHandler.postDelayed(mHideGuideOverlayRunnable, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
     }
@@ -109,7 +71,6 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        sPipOverlayActivity = null;
         mHandler.removeCallbacksAndMessages(null);
         mPipManager.removeListener(this);
         mPipManager.resumePipResizing(
@@ -140,32 +101,4 @@
         mPipManager.suspendPipResizing(
                 PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
     }
-
-    @Override
-    public void onMediaControllerChanged() {
-        updateGuideButtonsView();
-    }
-
-    @Override
-    public void finish() {
-        sPipOverlayActivity = null;
-        super.finish();
-    }
-
-    private void updateGuideButtonsView() {
-        switch (mPipManager.getPlaybackState()) {
-            case PipManager.PLAYBACK_STATE_PLAYING:
-                mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
-                mGuideButtonPlayPauseImageView.setImageResource(R.drawable.ic_pause_white_24dp);
-                break;
-            case PipManager.PLAYBACK_STATE_PAUSED:
-                mGuideButtonPlayPauseImageView.setVisibility(View.VISIBLE);
-                mGuideButtonPlayPauseImageView.setImageResource(
-                        R.drawable.ic_play_arrow_white_24dp);
-                break;
-            case PipManager.PLAYBACK_STATE_UNAVAILABLE:
-                mGuideButtonPlayPauseImageView.setVisibility(View.GONE);
-                break;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
new file mode 100644
index 0000000..8b8c105
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -0,0 +1,169 @@
+/*
+ * 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.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
+import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
+
+/**
+ * An extended version of {@link PipControlsView} that supports animation in Recents.
+ */
+public class PipRecentsControlsView extends PipControlsView {
+    /**
+     * An interface to listen user action.
+     */
+    public interface Listener extends PipControlsView.Listener {
+        /**
+         * Called when an user presses BACK key and up.
+         */
+        abstract void onBackPressed();
+    }
+
+    private AnimatorSet mFocusGainAnimatorSet;
+    private AnimatorSet mFocusLoseAnimatorSet;
+
+    public PipRecentsControlsView(Context context) {
+        this(context, null, 0, 0);
+    }
+
+    public PipRecentsControlsView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0, 0);
+    }
+
+    public PipRecentsControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public PipRecentsControlsView(
+            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+
+        int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
+        int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
+        mFocusGainAnimatorSet = new AnimatorSet();
+        mFocusGainAnimatorSet.playTogether(
+                loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
+                loadAnimator(mFullButtonView,buttonsFocusGainAnim),
+                loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
+                loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
+                loadAnimator(mFullDescriptionView, textFocusGainAnim),
+                loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
+                loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+
+        int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
+        int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
+        mFocusLoseAnimatorSet = new AnimatorSet();
+        mFocusLoseAnimatorSet.playTogether(
+                loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
+                loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
+                loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
+                loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
+                loadAnimator(mFullDescriptionView, textFocusLoseAnim),
+                loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
+                loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+
+        Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
+        int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
+                R.dimen.recents_tv_pip_controls_margin_top);
+        setPadding(0, pipBounds.bottom + pipControlsMarginTop, 0, 0);
+    }
+
+    private Animator loadAnimator(View view, int animatorResId) {
+        Animator animator = AnimatorInflater.loadAnimator(getContext(), animatorResId);
+        animator.setTarget(view);
+        return animator;
+    }
+
+    /**
+     * Starts focus gaining animation.
+     */
+    public void startFocusGainAnimation() {
+        if (mFocusLoseAnimatorSet.isStarted()) {
+            mFocusLoseAnimatorSet.cancel();
+        }
+        mFocusGainAnimatorSet.start();
+    }
+
+    /**
+     * Starts focus losing animation.
+     */
+    public void startFocusLoseAnimation() {
+        if (mFocusGainAnimatorSet.isStarted()) {
+            mFocusGainAnimatorSet.cancel();
+        }
+        mFocusLoseAnimatorSet.start();
+    }
+
+    /**
+     * Resets the view to the initial state. (i.e. end of the focus gain)
+     */
+    public void reset() {
+        if (mFocusGainAnimatorSet.isStarted()) {
+            mFocusGainAnimatorSet.cancel();
+        }
+        if (mFocusLoseAnimatorSet.isStarted()) {
+            mFocusLoseAnimatorSet.cancel();
+        }
+
+        // Reset to initial state (i.e. end of focused)
+        requestFocus();
+        setTranslationY(0);
+        setScaleXY(mFullButtonView, 1);
+        setScaleXY(mPlayPauseButtonImageView, 1);
+        setScaleXY(mCloseButtonView, 1);
+        mFullDescriptionView.setAlpha(1);
+        mPlayPauseDescriptionTextView.setAlpha(1);
+        mCloseDescriptionView.setAlpha(1);
+    }
+
+    private void setScaleXY(View view, float scale) {
+        view.setScaleX(scale);
+        view.setScaleY(scale);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (!event.isCanceled()
+                && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+                && event.getAction() == KeyEvent.ACTION_UP) {
+            if (mListener != null) {
+                ((PipRecentsControlsView.Listener) mListener).onBackPressed();
+            }
+            return true;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
new file mode 100644
index 0000000..b90b727
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -0,0 +1,207 @@
+/*
+ * 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.tv.pip;
+
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_OVERLAY;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS;
+import static com.android.systemui.tv.pip.PipManager.STATE_PIP_RECENTS_FOCUSED;
+
+public class PipRecentsOverlayManager {
+    private static final String TAG = "PipRecentsOverlayManager";
+
+    public interface Callback {
+        void onClosed();
+        void onBackPressed();
+        void onRecentsFocused();
+    }
+
+    private final PipManager mPipManager = PipManager.getInstance();
+    private final WindowManager mWindowManager;
+    private final View mOverlayView;
+    private final PipRecentsControlsView mPipControlsView;
+    private final View mRecentsView;
+
+    private final LayoutParams mPipRecentsControlsViewLayoutParams;
+    private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
+
+    private boolean mIsPipRecentsOverlayShown;
+    private boolean mIsRecentsShown;
+    private boolean mIsPipFocusedInRecent;
+    private Callback mCallback;
+    private PipRecentsControlsView.Listener mPipControlsViewListener =
+            new PipRecentsControlsView.Listener() {
+                @Override
+                public void onClosed() {
+                    if (mCallback != null) {
+                        mCallback.onClosed();
+                    }
+                }
+
+                @Override
+                public void onBackPressed() {
+                    if (mCallback != null) {
+                        mCallback.onBackPressed();
+                    }
+                }
+            };
+
+    PipRecentsOverlayManager(Context context) {
+        mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
+
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mOverlayView = inflater.inflate(R.layout.tv_pip_recents_overlay, null);
+        mPipControlsView = (PipRecentsControlsView) mOverlayView.findViewById(R.id.pip_controls);
+        mRecentsView = mOverlayView.findViewById(R.id.recents);
+        mRecentsView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (hasFocus) {
+                    clearFocus();
+                }
+            }
+        });
+
+        mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_SYSTEM_DIALOG,
+                LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
+                PixelFormat.TRANSLUCENT);
+        mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_SYSTEM_DIALOG,
+                0,
+                PixelFormat.TRANSLUCENT);
+    }
+
+    /**
+     * Add Recents overlay view.
+     * This is expected to be called after the PIP animation is over.
+     */
+    void addPipRecentsOverlayView() {
+        if (mIsPipRecentsOverlayShown) {
+            return;
+        }
+        mIsPipRecentsOverlayShown = true;
+        mIsPipFocusedInRecent = true;
+        mPipControlsView.reset();
+        mWindowManager.addView(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+    }
+
+    /**
+     * Remove Recents overlay view.
+     * This should be called when Recents or PIP is closed.
+     */
+    public void removePipRecentsOverlayView() {
+        if (!mIsPipRecentsOverlayShown) {
+            return;
+        }
+        mWindowManager.removeView(mOverlayView);
+        mIsPipRecentsOverlayShown = false;
+    }
+
+    /**
+     * Request focus to the PIP Recents overlay.
+     * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+     * is focused.
+     * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+     * @param hasRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
+     */
+    public void requestFocus(boolean hasRecentsFocusable) {
+        if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+            return;
+        }
+        mIsPipFocusedInRecent = true;
+        mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+
+        mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
+        mPipControlsView.requestFocus();
+        mPipControlsView.startFocusGainAnimation();
+        mRecentsView.setVisibility(hasRecentsFocusable ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Request focus to the PIP Recents overlay.
+     * Called when the PIP view in {@link com.android.systemui.recents.tv.RecentsTvActivity}
+     * is focused.
+     * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
+     */
+    private void clearFocus() {
+        if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+            return;
+        }
+        mIsPipFocusedInRecent = false;
+        mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
+        mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
+        mPipControlsView.startFocusLoseAnimation();
+        if (mCallback != null) {
+            mCallback.onRecentsFocused();
+        }
+    }
+
+    public void setCallback(Callback listener) {
+        mCallback = listener;
+        mPipControlsView.setListener(mCallback != null ? mPipControlsViewListener : null);
+    }
+
+    /**
+     * Called when Recents is resumed.
+     * PIPed activity will be resized accordingly and overlay will show available buttons.
+     */
+    public void onRecentsResumed() {
+        if (!mPipManager.isPipShown()) {
+            return;
+        }
+        mIsRecentsShown = true;
+        mIsPipFocusedInRecent = true;
+        mPipManager.resizePinnedStack(STATE_PIP_RECENTS_FOCUSED);
+        // Overlay view will be added after the resize animation ends, if any.
+    }
+
+    /**
+     * Called when Recents is paused.
+     * PIPed activity will be resized accordingly and overlay will hide available buttons.
+     */
+    public void onRecentsPaused() {
+        mIsRecentsShown = false;
+        mIsPipFocusedInRecent = false;
+        removePipRecentsOverlayView();
+
+        if (mPipManager.isPipShown()) {
+            mPipManager.resizePinnedStack(STATE_PIP_OVERLAY);
+        }
+    }
+
+    /**
+     * Returns {@code true} if recents is shown.
+     */
+    boolean isRecentsShown() {
+        return mIsRecentsShown;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index f432808..c6e4356 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -35,11 +35,11 @@
     private static final Typeface MEDIUM = Typeface.create("sans-serif-medium", Typeface.NORMAL);
 
     private final Context mContext;
-    private final LayoutInflater mInflater;
+    protected final LayoutInflater mInflater;
     private final SpTexts mSpTexts;
 
     private Callback mCallback;
-    private Object mSelectedValue;
+    protected Object mSelectedValue;
 
     public SegmentedButtons(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -65,13 +65,21 @@
             final Object tag = c.getTag();
             final boolean selected = Objects.equals(mSelectedValue, tag);
             c.setSelected(selected);
-            c.setTypeface(selected ? MEDIUM : REGULAR);
+            setSelectedStyle(c, selected);
         }
         fireOnSelected(fromClick);
     }
 
+    protected void setSelectedStyle(TextView textView, boolean selected) {
+        textView.setTypeface(selected ? MEDIUM : REGULAR);
+    }
+
+    public Button inflateButton() {
+        return (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+    }
+
     public void addButton(int labelResId, int contentDescriptionResId, Object value) {
-        final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+        final Button b = inflateButton();
         b.setTag(LABEL_RES_KEY, labelResId);
         b.setText(labelResId);
         b.setContentDescription(getResources().getString(contentDescriptionResId));
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 32e1e6d..08257b6 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <application android:label="VpnDialogs"
             android:allowBackup="false" >
         <activity android:name=".ConfirmDialog"
-                android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert">
+                android:theme="@android:style/Theme.Material.Light.Dialog.Alert">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.DEFAULT"/>
@@ -32,7 +32,7 @@
         </activity>
 
         <activity android:name=".ManageDialog"
-                android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"
+                android:theme="@android:style/Theme.Material.Light.Dialog.Alert"
                 android:noHistory="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index 0f9e247..6a56afd 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources>
-    <style name="Theme.WallpaperCropper" parent="@*android:style/Theme.Material.DayNight">
+    <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Material.Light">
         <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowActionBarOverlay">true</item>
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 8e4bf24..b3613df 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2080,6 +2080,61 @@
     // OS: N
     SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371;
 
+    // ------- Begin N Settings conditionals -----
+    // Conditionals are the green bars at the top of the settings dashboard
+    // All conditionals will have visible/hide events onResume/onPause
+    // but they will also be used as extra ints in the
+    // dismiss/expand/collapse/click/button events
+
+    // swipe away conditional
+    ACTION_SETTINGS_CONDITION_DISMISS = 372;
+
+    // click on collapsed conditional or clicks expand button
+    ACTION_SETTINGS_CONDITION_EXPAND = 373;
+
+    // click collapse button on expanded conditional
+    ACTION_SETTINGS_CONDITION_COLLAPSE = 374;
+
+    // click main area of expanded conditional
+    ACTION_SETTINGS_CONDITION_CLICK = 375;
+
+    // click a direct button on expanded conditional
+    ACTION_SETTINGS_CONDITION_BUTTON = 376;
+
+    // Airplane mode on
+    SETTINGS_CONDITION_AIRPLANE_MODE = 377;
+    // AKA Data saver on
+    SETTINGS_CONDITION_BACKGROUND_DATA = 378;
+    // Battery saver on
+    SETTINGS_CONDITION_BATTERY_SAVER = 379;
+    // Cellular data off
+    SETTINGS_CONDITION_CELLULAR_DATA = 380;
+    // Do not disturb on
+    SETTINGS_CONDITION_DND = 381;
+    // Hotspot on
+    SETTINGS_CONDITION_HOTSPOT = 382;
+    // Work profile off
+    SETTINGS_CONDITION_WORK_MODE = 383;
+
+    // ------- Begin N Settings suggestions -----
+    // Since suggestions come from system apps, suggestions will
+    // have generic constants and the package providing the suggestion
+    // will be put in the package field.  For suggestions in the Settings
+    // package, the class name will be filled in instead (since settings
+    // provides several suggetions).
+
+    // Settings shown/hidden on main settings dashboard.
+    // These are actually visibility events, but visible/hidden doesn't
+    // take a package, so these are being logged as actions.
+    ACTION_SHOW_SETTINGS_SUGGESTION = 384;
+    ACTION_HIDE_SETTINGS_SUGGESTION = 385;
+
+    // Click on a suggestion.
+    ACTION_SETTINGS_SUGGESTION = 386;
+
+    // Suggestion -> Overflow -> Remove.
+    ACTION_SETTINGS_DISMISS_SUGGESTION = 387;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 81f63ae..9ec6e8d 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -380,6 +380,7 @@
             Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
             throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
         }
+        guard.open("destroy");
     }
 
     Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
@@ -1915,6 +1916,7 @@
             if (type.getID(rs) == 0) {
                 throw new RSInvalidStateException("Bad Type");
             }
+            // TODO: What if there is an exception after this? The native allocation would leak.
             long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
             if (id == 0) {
                 throw new RSRuntimeException("Allocation creation failed.");
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index 1372ab7..f95af16 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,6 +16,7 @@
 
 package android.renderscript;
 
+import dalvik.system.CloseGuard;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
@@ -69,6 +70,7 @@
     }
 
     private long mID;
+    final CloseGuard guard = CloseGuard.get();
     private boolean mDestroyed;
     private String mName;
     RenderScript mRS;
@@ -119,6 +121,7 @@
         }
 
         if (shouldDestroy) {
+            guard.close();
             // must include nObjDestroy in the critical section
             ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
             rlock.lock();
@@ -133,8 +136,14 @@
     }
 
     protected void finalize() throws Throwable {
-        helpDestroy();
-        super.finalize();
+        try {
+            if (guard != null) {
+                guard.warnIfOpen();
+            }
+            helpDestroy();
+        } finally {
+            super.finalize();
+        }
     }
 
     /**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 6efb6d6..50226ac 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -808,6 +808,7 @@
             mSize += mElements[ct].mSize * mArraySizes[ct];
         }
         updateVisibleSubElements();
+        guard.open("destroy");
     }
 
     Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -827,6 +828,7 @@
         mKind = dk;
         mNormalized = norm;
         mVectorSize = size;
+        guard.open("destroy");
     }
 
     Element(long id, RenderScript rs) {
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 9d8f162..278d309 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -170,6 +170,7 @@
     FileA3D(long id, RenderScript rs, InputStream stream) {
         super(id, rs);
         mInputStream = stream;
+        guard.open("destroy");
     }
 
     private void initEntries() {
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 4318b9d..d5ca31e 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -150,6 +150,7 @@
 
     Font(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 13c8e1c..9e4f905 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -91,6 +91,7 @@
 
     Mesh(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index 3eb9b75..772021c 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -76,6 +76,7 @@
 
     Program(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java
index a4edbb5..5c4bae9 100644
--- a/rs/java/android/renderscript/Sampler.java
+++ b/rs/java/android/renderscript/Sampler.java
@@ -51,6 +51,7 @@
 
     Sampler(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index f6f93cb..fc3280b 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -41,6 +41,7 @@
             mScript = s;
             mSlot = slot;
             mSig = sig;
+            guard.open("destroy");
         }
     }
 
@@ -118,6 +119,7 @@
             super(id, rs);
             mScript = s;
             mSlot = slot;
+            guard.open("destroy");
         }
     }
 
@@ -357,6 +359,19 @@
         super(id, rs);
 
         mInIdsBuffer = new long[1];
+
+        /* The constructors for the derived classes (including ScriptIntrinsic
+         * derived classes and ScriptC derived classes generated by Slang
+         * reflection) seem to be simple enough, so we just put the guard.open()
+         * call here, rather than in the end of the constructor for the derived
+         * class. This, of course, assumes the derived constructor would not
+         * throw any exception after calling this constructor.
+         *
+         * If new derived classes are added with more complicated constructors
+         * that throw exceptions, this call has to be (duplicated and) moved
+         * to the end of each derived class constructor.
+         */
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 9357c3bb..219f16b 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -148,6 +148,8 @@
                                         fieldIDs, values, sizes, depClosures, depFieldIDs);
 
             setID(id);
+
+            guard.open("destroy");
         }
 
         Closure(RenderScript rs, Script.InvokeID invokeID,
@@ -181,6 +183,8 @@
                                               values, sizes);
 
             setID(id);
+
+            guard.open("destroy");
         }
 
         private void retrieveValueAndDependenceInfo(RenderScript rs,
@@ -382,6 +386,7 @@
 
     ScriptGroup(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     ScriptGroup(RenderScript rs, String name, List<Closure> closures,
@@ -398,6 +403,7 @@
         }
         long id = rs.nScriptGroup2Create(name, RenderScript.getCachePath(), closureIDs);
         setID(id);
+        guard.open("destroy");
     }
 
     /**
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index dc23785..9252898 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -227,6 +227,7 @@
 
     Type(long id, RenderScript rs) {
         super(id, rs);
+        guard.open("destroy");
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4b96e7a..e256ecd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1262,7 +1262,7 @@
             Service service = componentNameToServiceMap.get(componentName);
 
             // Ignore non-encryption-aware services until user is unlocked
-            if (!isUnlocked && !installedService.isEncryptionAware()) {
+            if (!isUnlocked && !installedService.isDirectBootAware()) {
                 Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
                 continue;
             }
@@ -1784,10 +1784,15 @@
                     userState.mEnabledServices.contains(userState.mServiceChangingSoftKeyboardMode);
 
             if (!serviceChangingSoftKeyboardModeIsEnabled) {
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
-                        0,
-                        userState.mUserId);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+                            0,
+                            userState.mUserId);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
                 userState.mSoftKeyboardShowMode = 0;
                 userState.mServiceChangingSoftKeyboardMode = null;
             }
@@ -3491,6 +3496,8 @@
             reportedWindow.setLayer(window.layer);
             reportedWindow.setFocused(window.focused);
             reportedWindow.setBoundsInScreen(window.boundsInScreen);
+            reportedWindow.setTitle(window.title);
+            reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
 
             final int parentId = findWindowIdLocked(window.parentToken);
             if (parentId >= 0) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 215be4a..89b145e 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -486,8 +486,14 @@
                 boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
                 changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
                 try {
-                    boolean suspended = mPackageManager.isPackageSuspendedForUser(
-                            provider.info.provider.getPackageName(), provider.getUserId());
+                    boolean suspended;
+                    try {
+                        suspended = mPackageManager.isPackageSuspendedForUser(
+                                provider.info.provider.getPackageName(), provider.getUserId());
+                    } catch (IllegalArgumentException ex) {
+                        // Package not found.
+                        suspended = false;
+                    }
                     changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to query application info", e);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 57ba1b9..c38a89e 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -446,8 +446,12 @@
             int[] ops) {
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return Collections.emptyList();
+        }
         synchronized (this) {
-            Ops pkgOps = getOpsLocked(uid, packageName, false);
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
             if (pkgOps == null) {
                 return null;
             }
@@ -465,7 +469,7 @@
 
     private void pruneOp(Op op, int uid, String packageName) {
         if (op.time == 0 && op.rejectTime == 0) {
-            Ops ops = getOpsLocked(uid, packageName, false);
+            Ops ops = getOpsRawLocked(uid, packageName, false);
             if (ops != null) {
                 ops.remove(op.op);
                 if (ops.size() <= 0) {
@@ -879,8 +883,12 @@
     public int checkOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
         synchronized (this) {
-            if (isOpRestricted(uid, code, packageName)) {
+            if (isOpRestricted(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -891,7 +899,7 @@
                     return uidMode;
                 }
             }
-            Op op = getOpLocked(code, uid, packageName, false);
+            Op op = getOpLocked(code, uid, resolvedPackageName, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
@@ -901,7 +909,15 @@
 
     @Override
     public int checkAudioOperation(int code, int usage, int uid, String packageName) {
-        if (isPackageSuspendedForUser(packageName, uid)) {
+        boolean suspended;
+        try {
+            suspended = isPackageSuspendedForUser(packageName, uid);
+        } catch (IllegalArgumentException ex) {
+            // Package not found.
+            suspended = false;
+        }
+
+        if (suspended) {
             Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
             return AppOpsManager.MODE_IGNORED;
         }
@@ -967,6 +983,7 @@
 
     @Override
     public int checkPackage(int uid, String packageName) {
+        Preconditions.checkNotNull(packageName);
         synchronized (this) {
             if (getOpsRawLocked(uid, packageName, true) != null) {
                 return AppOpsManager.MODE_ALLOWED;
@@ -980,26 +997,39 @@
     public int noteProxyOperation(int code, String proxyPackageName,
             int proxiedUid, String proxiedPackageName) {
         verifyIncomingOp(code);
-        final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
-                proxyPackageName, -1, null);
+        final int proxyUid = Binder.getCallingUid();
+        String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+        if (resolveProxyPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        final int proxyMode = noteOperationUnchecked(code, proxyUid,
+                resolveProxyPackageName, -1, null);
         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
             return proxyMode;
         }
-        return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
-                Binder.getCallingUid(), proxyPackageName);
+        String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+        if (resolveProxiedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
+                proxyMode, resolveProxyPackageName);
     }
 
     @Override
     public int noteOperation(int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        return noteOperationUnchecked(code, uid, packageName, 0, null);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
     }
 
     private int noteOperationUnchecked(int code, int uid, String packageName,
             int proxyUid, String proxyPackageName) {
         synchronized (this) {
-            Ops ops = getOpsLocked(uid, packageName, true);
+            Ops ops = getOpsRawLocked(uid, packageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName);
@@ -1047,16 +1077,20 @@
     public int startOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return  AppOpsManager.MODE_IGNORED;
+        }
         ClientState client = (ClientState)token;
         synchronized (this) {
-            Ops ops = getOpsLocked(uid, packageName, true);
+            Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
             if (ops == null) {
                 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
-                        + " package " + packageName);
+                        + " package " + resolvedPackageName);
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, packageName)) {
+            if (isOpRestricted(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1066,7 +1100,7 @@
                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName);
+                            + resolvedPackageName);
                     op.rejectTime = System.currentTimeMillis();
                     return uidMode;
                 }
@@ -1074,12 +1108,13 @@
             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
                 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
-                        + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+                        + switchCode + " (" + code + ") uid " + uid + " package "
+                        + resolvedPackageName);
                 op.rejectTime = System.currentTimeMillis();
                 return switchOp.mode;
             }
             if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
-                    + " package " + packageName);
+                    + " package " + resolvedPackageName);
             if (op.nesting == 0) {
                 op.time = System.currentTimeMillis();
                 op.rejectTime = 0;
@@ -1097,9 +1132,16 @@
     public void finishOperation(IBinder token, int code, int uid, String packageName) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
-        ClientState client = (ClientState)token;
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return;
+        }
+        if (!(token instanceof ClientState)) {
+            return;
+        }
+        ClientState client = (ClientState) token;
         synchronized (this) {
-            Op op = getOpLocked(code, uid, packageName, true);
+            Op op = getOpLocked(code, uid, resolvedPackageName, true);
             if (op == null) {
                 return;
             }
@@ -1115,6 +1157,9 @@
 
     @Override
     public int permissionToOpCode(String permission) {
+        if (permission == null) {
+            return AppOpsManager.OP_NONE;
+        }
         return AppOpsManager.permissionToOpCode(permission);
     }
 
@@ -1164,15 +1209,6 @@
         return uidState;
     }
 
-    private Ops getOpsLocked(int uid, String packageName, boolean edit) {
-        if (uid == 0) {
-            packageName = "root";
-        } else if (uid == Process.SHELL_UID) {
-            packageName = "com.android.shell";
-        }
-        return getOpsRawLocked(uid, packageName, edit);
-    }
-
     private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
@@ -1258,7 +1294,7 @@
     }
 
     private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
-        Ops ops = getOpsLocked(uid, packageName, edit);
+        Ops ops = getOpsRawLocked(uid, packageName, edit);
         if (ops == null) {
             return null;
         }
@@ -1316,7 +1352,7 @@
                 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
                     // If we are the system, bypass user restrictions for certain codes
                     synchronized (this) {
-                        Ops ops = getOpsLocked(uid, packageName, true);
+                        Ops ops = getOpsRawLocked(uid, packageName, true);
                         if ((ops != null) && ops.isPrivileged) {
                             return false;
                         }
@@ -1581,7 +1617,7 @@
                         out.startTag(null, "uid");
                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
                         synchronized (this) {
-                            Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
+                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
                             // Should always be present as the list of PackageOps is generated
                             // from Ops.
                             if (ops != null) {
@@ -2173,6 +2209,7 @@
     @Override
     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
         checkSystemUid("setUserRestrictions");
+        Preconditions.checkNotNull(restrictions);
         Preconditions.checkNotNull(token);
         final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
         for (int i = 0; i < opRestrictions.length; ++i) {
@@ -2387,6 +2424,17 @@
         }
     }
 
+    private static String resolvePackageName(int uid, String packageName)  {
+        if (uid == 0) {
+            return "root";
+        } else if (uid == Process.SHELL_UID) {
+            return "com.android.shell";
+        } else if (uid == Process.SYSTEM_UID && packageName == null) {
+            return "android";
+        }
+        return packageName;
+    }
+
     private static String[] getPackagesForUid(int uid) {
         String[] packageNames = null;
         try {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 799a763..0a814ab 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -92,6 +92,7 @@
     private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
     private static final int MESSAGE_TIMEOUT_BIND = 100;
     private static final int MESSAGE_TIMEOUT_UNBIND = 101;
+    private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
     private static final int MESSAGE_USER_SWITCHED = 300;
     private static final int MESSAGE_USER_UNLOCKED = 301;
     private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
@@ -599,8 +600,8 @@
             sendEnableMsg(true);
         }
         return true;
-
     }
+
     public boolean enable() {
         if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
             (!checkIfCallerIsForegroundUser())) {
@@ -763,9 +764,8 @@
             sendEnableMsg(mQuietEnableExternal);
         } else if (!isNameAndAddressSet()) {
             if (DBG) Slog.d(TAG, "Getting adapter name and address");
-            enable();
-            waitForOnOff(true, false);
-            disable(true);
+            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+            mHandler.sendMessage(getMsg);
         }
     }
 
@@ -1076,6 +1076,8 @@
     private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
 
     private class BluetoothHandler extends Handler {
+        boolean mGetNameAddressOnly = false;
+
         public BluetoothHandler(Looper looper) {
             super(looper);
         }
@@ -1084,6 +1086,37 @@
         public void handleMessage(Message msg) {
             if (DBG) Slog.d (TAG, "Message: " + msg.what);
             switch (msg.what) {
+                case MESSAGE_GET_NAME_AND_ADDRESS:
+                    if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+                    synchronized(mConnection) {
+                        if ((mBluetooth == null) && (!mBinding)) {
+                            if (DBG) Slog.d(TAG, "Binding to service to get name and address");
+                            mGetNameAddressOnly = true;
+                            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+                            mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
+                            Intent i = new Intent(IBluetooth.class.getName());
+                            if (!doBind(i, mConnection,
+                                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+                                UserHandle.CURRENT)) {
+                                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+                            } else {
+                                mBinding = true;
+                            }
+                        } else if (mBluetooth != null) {
+                            try {
+                                storeNameAndAddress(mBluetooth.getName(),
+                                                    mBluetooth.getAddress());
+                            } catch (RemoteException re) {
+                                Slog.e(TAG, "Unable to grab names", re);
+                            }
+                            if (mGetNameAddressOnly && !mEnable) {
+                                unbindAndFinish();
+                            }
+                            mGetNameAddressOnly = false;
+                        }
+                    }
+                    break;
+
                 case MESSAGE_ENABLE:
                     if (DBG) {
                         Slog.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
@@ -1177,6 +1210,12 @@
                         mBluetoothBinder = service;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
+                        if (!isNameAndAddressSet()) {
+                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+                            mHandler.sendMessage(getMsg);
+                            if (mGetNameAddressOnly) return;
+                        }
+
                         try {
                             boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
                                 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
@@ -1187,15 +1226,6 @@
                             Slog.e(TAG,"Unable to call configHciSnoopLog", e);
                         }
 
-                        if (!isNameAndAddressSet()) {
-                            try {
-                                storeNameAndAddress(mBluetooth.getName(),
-                                                    mBluetooth.getAddress());
-                            } catch (RemoteException re) {
-                                Slog.e(TAG, "Unable to grab names", re);
-                            }
-                        }
-
                         //Register callback object
                         try {
                             mBluetooth.registerCallback(mBluetoothCallback);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 6023d7f..423f945 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -113,6 +113,7 @@
     private AlarmManager mAlarmManager;
     private IBatteryStats mBatteryStats;
     private PowerManagerInternal mLocalPowerManager;
+    private PowerManager mPowerManager;
     private AlarmManagerService.LocalService mLocalAlarmManager;
     private INetworkPolicyManager mNetworkPolicyManager;
     private DisplayManager mDisplayManager;
@@ -168,16 +169,19 @@
     private static final int LIGHT_STATE_ACTIVE = 0;
     /** Device is inactive (screen off) and we are waiting to for the first light idle. */
     private static final int LIGHT_STATE_INACTIVE = 1;
+    /** Device is about to go idle for the first time, wait for current work to complete. */
+    private static final int LIGHT_STATE_PRE_IDLE = 3;
     /** Device is in the light idle state, trying to stay asleep as much as possible. */
-    private static final int LIGHT_STATE_IDLE = 2;
+    private static final int LIGHT_STATE_IDLE = 4;
     /** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
-    private static final int LIGHT_STATE_IDLE_MAINTENANCE = 3;
+    private static final int LIGHT_STATE_IDLE_MAINTENANCE = 5;
     /** Device light idle state is overriden, now applying deep doze state. */
-    private static final int LIGHT_STATE_OVERRIDE = 4;
+    private static final int LIGHT_STATE_OVERRIDE = 6;
     private static String lightStateToString(int state) {
         switch (state) {
             case LIGHT_STATE_ACTIVE: return "ACTIVE";
             case LIGHT_STATE_INACTIVE: return "INACTIVE";
+            case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
             case LIGHT_STATE_IDLE: return "IDLE";
             case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
             case LIGHT_STATE_OVERRIDE: return "OVERRIDE";
@@ -198,6 +202,7 @@
     private long mMaintenanceStartTime;
 
     private int mActiveIdleOpCount;
+    private PowerManager.WakeLock mActiveIdleWakeLock;
     private IBinder mDownloadServiceActive;
     private boolean mJobsActive;
     private boolean mAlarmsActive;
@@ -344,21 +349,18 @@
         }
     };
 
-    private final AlarmManager.OnAlarmListener mMaintenanceMinCheckListener
-            = new AlarmManager.OnAlarmListener() {
-        @Override
-        public void onAlarm() {
-            synchronized (DeviceIdleController.this) {
-                exitMaintenanceEarlyIfNeededLocked();
-            }
-        }
-    };
-
-    private boolean mMaintenanceMinCheckScheduled;
-
     private final BroadcastReceiver mIdleStartedDoneReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
-            decActiveIdleOps();
+            // When coming out of a deep idle, we will add in some delay before we allow
+            // the system to settle down and finish the maintenance window.  This is
+            // to give a chance for any pending work to be scheduled.
+            if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+                mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
+                        mConstants.MIN_DEEP_MAINTENANCE_TIME);
+            } else {
+                mHandler.sendEmptyMessageDelayed(MSG_FINISH_IDLE_OP,
+                        mConstants.MIN_LIGHT_MAINTENANCE_TIME);
+            }
         }
     };
 
@@ -482,6 +484,7 @@
         // Key names stored in the settings value.
         private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
                 = "light_after_inactive_to";
+        private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
         private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
         private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
         private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
@@ -520,6 +523,15 @@
         public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
 
         /**
+         * This is amount of time we will wait from the point where we decide we would
+         * like to go idle until we actually do, while waiting for jobs and other current
+         * activity to finish.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_LIGHT_PRE_IDLE_TIMEOUT
+         */
+        public long LIGHT_PRE_IDLE_TIMEOUT;
+
+        /**
          * This is the initial time that we will run in idle maintenance mode.
          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
          * @see #KEY_LIGHT_IDLE_TIMEOUT
@@ -747,6 +759,8 @@
                 LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(
                         KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
                         !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
+                LIGHT_PRE_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_PRE_IDLE_TIMEOUT,
+                        !COMPRESS_TIME ? 10 * 60 * 1000L : 30 * 1000L);
                 LIGHT_IDLE_TIMEOUT = mParser.getLong(KEY_LIGHT_IDLE_TIMEOUT,
                         !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L);
                 LIGHT_IDLE_FACTOR = mParser.getFloat(KEY_LIGHT_IDLE_FACTOR,
@@ -809,6 +823,10 @@
             TimeUtils.formatDuration(LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, pw);
             pw.println();
 
+            pw.print("    "); pw.print(KEY_LIGHT_PRE_IDLE_TIMEOUT); pw.print("=");
+            TimeUtils.formatDuration(LIGHT_PRE_IDLE_TIMEOUT, pw);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_LIGHT_IDLE_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
             pw.println();
@@ -939,6 +957,7 @@
     static final int MSG_REPORT_ACTIVE = 5;
     static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6;
     static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
+    static final int MSG_FINISH_IDLE_OP = 8;
 
     final class MyHandler extends Handler {
         MyHandler(Looper looper) {
@@ -1043,6 +1062,9 @@
                         mMaintenanceActivityListeners.finishBroadcast();
                     }
                 } break;
+                case MSG_FINISH_IDLE_OP: {
+                    decActiveIdleOps();
+                } break;
             }
         }
     }
@@ -1299,6 +1321,10 @@
                 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
                 mBatteryStats = BatteryStatsService.getService();
                 mLocalPowerManager = getLocalService(PowerManagerInternal.class);
+                mPowerManager = getContext().getSystemService(PowerManager.class);
+                mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                        "deviceidle_maint");
+                mActiveIdleWakeLock.setReferenceCounted(false);
                 mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
                 mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
                         ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
@@ -1687,10 +1713,6 @@
             mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
             mCurIdleBudget = 0;
             mMaintenanceStartTime = 0;
-            if (mMaintenanceMinCheckScheduled) {
-                mAlarmManager.cancel(mMaintenanceMinCheckListener);
-                mMaintenanceMinCheckScheduled = false;
-            }
             resetIdleManagementLocked();
             resetLightIdleManagementLocked();
             addEvent(EVENT_NORMAL);
@@ -1758,6 +1780,16 @@
                 // Reset the upcoming idle delays.
                 mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
                 mMaintenanceStartTime = 0;
+                if (!isOpsInactiveLocked()) {
+                    // We have some active ops going on...  give them a chance to finish
+                    // before going in to our first idle.
+                    mLightState = LIGHT_STATE_PRE_IDLE;
+                    EventLogTags.writeDeviceIdleLight(mLightState, reason);
+                    scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
+                    break;
+                }
+                // Nothing active, fall through to immediately idle.
+            case LIGHT_STATE_PRE_IDLE:
             case LIGHT_STATE_IDLE_MAINTENANCE:
                 if (mMaintenanceStartTime != 0) {
                     long duration = SystemClock.elapsedRealtime() - mMaintenanceStartTime;
@@ -1781,14 +1813,11 @@
                 EventLogTags.writeDeviceIdleLight(mLightState, reason);
                 addEvent(EVENT_LIGHT_IDLE);
                 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
-                if (mMaintenanceMinCheckScheduled) {
-                    mAlarmManager.cancel(mMaintenanceMinCheckListener);
-                    mMaintenanceMinCheckScheduled = false;
-                }
                 break;
             case LIGHT_STATE_IDLE:
                 // We have been idling long enough, now it is time to do some work.
                 mActiveIdleOpCount = 1;
+                mActiveIdleWakeLock.acquire();
                 mMaintenanceStartTime = SystemClock.elapsedRealtime();
                 if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
                     mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
@@ -1802,10 +1831,6 @@
                 EventLogTags.writeDeviceIdleLight(mLightState, reason);
                 addEvent(EVENT_LIGHT_MAINTENANCE);
                 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
-                mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME,
-                        mMaintenanceStartTime + mConstants.MIN_LIGHT_MAINTENANCE_TIME,
-                        "DeviceIdleController.maint-check", mMaintenanceMinCheckListener, mHandler);
-                mMaintenanceMinCheckScheduled = true;
                 break;
         }
     }
@@ -1901,14 +1926,11 @@
                 EventLogTags.writeDeviceIdle(mState, reason);
                 addEvent(EVENT_DEEP_IDLE);
                 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
-                if (mMaintenanceMinCheckScheduled) {
-                    mAlarmManager.cancel(mMaintenanceMinCheckListener);
-                    mMaintenanceMinCheckScheduled = false;
-                }
                 break;
             case STATE_IDLE:
                 // We have been idling long enough, now it is time to do some work.
                 mActiveIdleOpCount = 1;
+                mActiveIdleWakeLock.acquire();
                 scheduleAlarmLocked(mNextIdlePendingDelay, false);
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
                         "Next alarm in " + mNextIdlePendingDelay + " ms.");
@@ -1922,10 +1944,6 @@
                 EventLogTags.writeDeviceIdle(mState, reason);
                 addEvent(EVENT_DEEP_MAINTENANCE);
                 mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
-                mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME,
-                        mMaintenanceStartTime + mConstants.MIN_DEEP_MAINTENANCE_TIME,
-                        "DeviceIdleController.maint-check", mMaintenanceMinCheckListener, mHandler);
-                mMaintenanceMinCheckScheduled = true;
                 break;
         }
     }
@@ -1941,6 +1959,7 @@
             mActiveIdleOpCount--;
             if (mActiveIdleOpCount <= 0) {
                 exitMaintenanceEarlyIfNeededLocked();
+                mActiveIdleWakeLock.release();
             }
         }
     }
@@ -2012,10 +2031,15 @@
         mHandler.sendMessage(msg);
     }
 
+    boolean isOpsInactiveLocked() {
+        return mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
+                && !mJobsActive && !mAlarmsActive;
+    }
+
     void exitMaintenanceEarlyIfNeededLocked() {
-        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
-            if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
-                    && !mJobsActive && !mAlarmsActive) {
+        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE
+                || mLightState == LIGHT_STATE_PRE_IDLE) {
+            if (isOpsInactiveLocked()) {
                 final long now = SystemClock.elapsedRealtime();
                 if (DEBUG) {
                     StringBuilder sb = new StringBuilder();
@@ -2026,13 +2050,11 @@
                     Slog.d(TAG, sb.toString());
                 }
                 if (mState == STATE_IDLE_MAINTENANCE) {
-                    if (now >= (mMaintenanceStartTime + mConstants.MIN_DEEP_MAINTENANCE_TIME)) {
-                        stepIdleStateLocked("s:early");
-                    }
+                    stepIdleStateLocked("s:early");
+                } else if (mLightState == LIGHT_STATE_PRE_IDLE) {
+                    stepLightIdleStateLocked("s:predone");
                 } else {
-                    if (now >= (mMaintenanceStartTime + mConstants.MIN_LIGHT_MAINTENANCE_TIME)) {
-                        stepLightIdleStateLocked("s:early");
-                    }
+                    stepLightIdleStateLocked("s:early");
                 }
             }
         }
@@ -2828,10 +2850,6 @@
                 TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
                 pw.println();
             }
-            if (mMaintenanceMinCheckScheduled) {
-                pw.print("  mMaintenanceMinCheckScheduled=");
-                pw.println(mMaintenanceMinCheckScheduled);
-            }
             if (mJobsActive) {
                 pw.print("  mJobsActive="); pw.println(mJobsActive);
             }
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index e29515f..ecbe1ca 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -51,7 +51,7 @@
  * 2) ASHMEM_SIZE (for scratch space used during dumping)
  * 3) ASHMEM_SIZE * HISTORY_SIZE
  *
- * This is currently under 16KiB total memory in the worst case of
+ * This is currently under 20KiB total memory in the worst case of
  * 20 processes in history + 10 unique active processes.
  *
  *  @hide */
@@ -59,7 +59,7 @@
     public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
 
     private static final String TAG = "GraphicsStatsService";
-    private static final int ASHMEM_SIZE = 296;
+    private static final int ASHMEM_SIZE = 464;
     private static final int HISTORY_SIZE = 20;
 
     private final Context mContext;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 77b3111..811e34e 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -125,6 +125,7 @@
 import android.widget.RadioButton;
 import android.widget.Switch;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -452,6 +453,7 @@
     private AlertDialog.Builder mDialogBuilder;
     private AlertDialog mSwitchingDialog;
     private View mSwitchingDialogTitleView;
+    private Toast mSubtypeSwitchedByShortCutToast;
     private InputMethodInfo[] mIms;
     private int[] mSubtypeIds;
     private LocaleList mLastSystemLocales;
@@ -2952,6 +2954,27 @@
                 return;
             }
             setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+            if (mSubtypeSwitchedByShortCutToast != null) {
+                mSubtypeSwitchedByShortCutToast.cancel();
+                mSubtypeSwitchedByShortCutToast = null;
+            }
+            if ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+                // IME window is shown.  The user should be able to visually understand that the
+                // subtype is changed in most of cases.  To avoid UI overlap, we do not show a toast
+                // in this case.
+                return;
+            }
+            final InputMethodInfo newInputMethodInfo = mMethodMap.get(mCurMethodId);
+            if (newInputMethodInfo == null) {
+                return;
+            }
+            final CharSequence toastText = InputMethodUtils.getImeAndSubtypeDisplayName(mContext,
+                    newInputMethodInfo, mCurrentSubtype);
+            if (!TextUtils.isEmpty(toastText)) {
+                mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText.toString(),
+                        Toast.LENGTH_SHORT);
+                mSubtypeSwitchedByShortCutToast.show();
+            }
         }
     }
 
@@ -3221,16 +3244,6 @@
             };
             mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
 
-            if (!isScreenLocked) {
-                final OnClickListener positiveListener = new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int whichButton) {
-                        showConfigureInputMethods();
-                    }
-                };
-                mDialogBuilder.setPositiveButton(
-                        com.android.internal.R.string.configure_input_methods, positiveListener);
-            }
             mSwitchingDialog = mDialogBuilder.create();
             mSwitchingDialog.setCanceledOnTouchOutside(true);
             mSwitchingDialog.getWindow().setType(
@@ -3833,6 +3846,22 @@
         }
     }
 
+    private static String imeWindowStatusToString(final int imeWindowVis) {
+        final StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        if ((imeWindowVis & InputMethodService.IME_ACTIVE) != 0) {
+            sb.append("Active");
+            first = false;
+        }
+        if ((imeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+            if (!first) {
+                sb.append("|");
+            }
+            sb.append("Visible");
+        }
+        return sb.toString();
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -3880,6 +3909,7 @@
             method = mCurMethod;
             p.println("  mCurMethod=" + mCurMethod);
             p.println("  mEnabledSession=" + mEnabledSession);
+            p.println("  mImeWindowVis=" + imeWindowStatusToString(mImeWindowVis));
             p.println("  mShowRequested=" + mShowRequested
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
                     + " mShowForced=" + mShowForced
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 9e2f1167..440d8b7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1231,7 +1231,8 @@
         }
 
         final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
         intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
         mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
@@ -1246,6 +1247,11 @@
     }
 
     private void onVolumeCreatedLocked(VolumeInfo vol) {
+        if (mPms.isOnlyCoreApps()) {
+            Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
+            return;
+        }
+
         if (vol.type == VolumeInfo.TYPE_EMULATED) {
             final StorageManager storage = mContext.getSystemService(StorageManager.class);
             final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
@@ -1347,7 +1353,8 @@
             intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
             intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
             intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
         }
 
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 11aef17..a44b065 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -30,16 +30,14 @@
 import android.os.Messenger;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.Base64;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
 import com.android.internal.util.AsyncChannel;
@@ -492,6 +490,7 @@
                         clientInfo.mResolvedService.setServiceName(name);
                         clientInfo.mResolvedService.setServiceType(type);
                         clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
+                        clientInfo.mResolvedService.setTxtRecords(cooked[6]);
 
                         stopResolveService(id);
                         removeRequestMap(clientId, id, clientInfo);
@@ -708,20 +707,9 @@
         if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
         try {
             Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
-                    service.getServiceType(), service.getPort());
-
-            // Add TXT records as additional arguments.
-            Map<String, byte[]> txtRecords = service.getAttributes();
-            for (String key : txtRecords.keySet()) {
-                try {
-                    // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
-                    byte[] recordValue = txtRecords.get(key);
-                    cmd.appendArg(String.format(Locale.US, "%s=%s", key,
-                            recordValue != null ? new String(recordValue, "UTF_8") : ""));
-                } catch (UnsupportedEncodingException e) {
-                    Slog.e(TAG, "Failed to encode txtRecord " + e);
-                }
-            }
+                    service.getServiceType(), service.getPort(),
+                    Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT)
+                            .replace("\n", ""));
 
             mNativeConnector.execute(cmd);
         } catch(NativeDaemonConnectorException e) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1632f92..8a0a62a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -65,6 +65,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -75,11 +76,13 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
@@ -91,6 +94,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
@@ -107,7 +111,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -126,7 +129,9 @@
     private static final String TAG = "AccountManagerService";
 
     private static final String DATABASE_NAME = "accounts.db";
-    private static final int DATABASE_VERSION = 9;
+    private static final int PRE_N_DATABASE_VERSION = 9;
+    private static final int CE_DATABASE_VERSION = 10;
+    private static final int DE_DATABASE_VERSION = 1;
 
     private static final int MAX_DEBUG_DB_SIZE = 64;
 
@@ -176,6 +181,15 @@
     private static final String META_VALUE = "value";
 
     private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+    private static final String SHARED_ACCOUNTS_ID = "_id";
+
+    private static final String PRE_N_DATABASE_NAME = "accounts.db";
+    private static final String CE_DATABASE_NAME = "accounts_ce.db";
+    private static final String DE_DATABASE_NAME = "accounts_de.db";
+    private static final String CE_DB_PREFIX = "ceDb.";
+    private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
+    private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
+    private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
 
     private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
             new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
@@ -214,7 +228,7 @@
 
     static class UserAccounts {
         private final int userId;
-        private final DatabaseHelper openHelper;
+        private final DeDatabaseHelper openHelper;
         private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
                 credentialsPermissionNotificationIds =
                 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
@@ -255,15 +269,15 @@
         UserAccounts(Context context, int userId) {
             this.userId = userId;
             synchronized (cacheLock) {
-                openHelper = new DatabaseHelper(context, userId);
+                openHelper = DeDatabaseHelper.create(context, userId);
             }
         }
     }
 
-    private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
+    private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
+    private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
 
-    private static AtomicReference<AccountManagerService> sThis =
-            new AtomicReference<AccountManagerService>();
+    private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
 
     /**
@@ -381,6 +395,11 @@
      */
     private void validateAccountsInternal(
             UserAccounts accounts, boolean invalidateAuthenticatorCache) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "validateAccountsInternal " + accounts.userId
+                    + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+                    + " userLocked=" + mUnlockedUsers.get(accounts.userId));
+        }
         if (invalidateAuthenticatorCache) {
             mAuthenticatorCache.invalidateCache(accounts.userId);
         }
@@ -453,8 +472,7 @@
                     null, null, null, null, ACCOUNTS_ID);
             try {
                 accounts.accountCache.clear();
-                final HashMap<String, ArrayList<String>> accountNamesByType =
-                        new LinkedHashMap<String, ArrayList<String>>();
+                final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
                 while (cursor.moveToNext()) {
                     final long accountId = cursor.getLong(0);
                     final String accountType = cursor.getString(1);
@@ -482,15 +500,12 @@
                         accountNames.add(accountName);
                     }
                 }
-                for (Map.Entry<String, ArrayList<String>> cur
-                        : accountNamesByType.entrySet()) {
+                for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
                     final String accountType = cur.getKey();
                     final ArrayList<String> accountNames = cur.getValue();
                     final Account[] accountsForType = new Account[accountNames.size()];
-                    int i = 0;
-                    for (String accountName : accountNames) {
-                        accountsForType[i] = new Account(accountName, accountType);
-                        ++i;
+                    for (int i = 0; i < accountsForType.length; i++) {
+                        accountsForType[i] = new Account(accountNames.get(i), accountType);
                     }
                     accounts.accountCache.put(accountType, accountsForType);
                 }
@@ -522,12 +537,25 @@
     protected UserAccounts getUserAccounts(int userId) {
         synchronized (mUsers) {
             UserAccounts accounts = mUsers.get(userId);
+            boolean validateAccounts = false;
             if (accounts == null) {
                 accounts = new UserAccounts(mContext, userId);
                 initializeDebugDbSizeAndCompileSqlStatementForLogging(
                         accounts.openHelper.getWritableDatabase(), accounts);
                 mUsers.append(userId, accounts);
                 purgeOldGrants(accounts);
+                validateAccounts = true;
+            }
+            // open CE database if necessary
+            if (!accounts.openHelper.isCeDatabaseAttached() && mUnlockedUsers.get(userId)) {
+                Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
+                synchronized (accounts.cacheLock) {
+                    CeDatabaseHelper.create(mContext, userId);
+                    accounts.openHelper.attachCeDatabase();
+                }
+                // TODO Synchronize accounts by removing CE account not available in DE
+            }
+            if (validateAccounts) {
                 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
             }
             return accounts;
@@ -571,27 +599,51 @@
         if (userId < 1) return;
 
         UserAccounts accounts;
+        boolean userUnlocked;
         synchronized (mUsers) {
             accounts = mUsers.get(userId);
             mUsers.remove(userId);
+            userUnlocked = mUnlockedUsers.get(userId);
+            mUnlockedUsers.delete(userId);
         }
-        if (accounts == null) {
-            File dbFile = new File(getDatabaseName(userId));
-            dbFile.delete();
-            return;
+        if (accounts != null) {
+            synchronized (accounts.cacheLock) {
+                accounts.openHelper.close();
+            }
         }
+        Log.i(TAG, "Removing database files for user " + userId);
+        File dbFile = new File(getDeDatabaseName(userId));
 
-        synchronized (accounts.cacheLock) {
-            accounts.openHelper.close();
-            File dbFile = new File(getDatabaseName(userId));
-            dbFile.delete();
+        deleteDbFileWarnIfFailed(dbFile);
+        // Remove CE file if user is unlocked, or FBE is not enabled
+        boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
+        if (!fbeEnabled || userUnlocked) {
+            File ceDb = new File(getCeDatabaseName(userId));
+            if (ceDb.exists()) {
+                deleteDbFileWarnIfFailed(ceDb);
+            }
+        }
+    }
+
+    private static void deleteDbFileWarnIfFailed(File dbFile) {
+        if (!SQLiteDatabase.deleteDatabase(dbFile)) {
+            Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
         }
     }
 
     private void onUserUnlocked(Intent intent) {
         int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "onUserUnlocked " + userId);
+        }
+        synchronized (mUsers) {
+            mUnlockedUsers.put(userId, true);
+        }
         if (userId < 1) return;
+        syncSharedAccounts(userId);
+    }
 
+    private void syncSharedAccounts(int userId) {
         // Check if there's a shared account that needs to be created as an account
         Account[] sharedAccounts = getSharedAccountsAsUser(userId);
         if (sharedAccounts == null || sharedAccounts.length == 0) return;
@@ -645,20 +697,15 @@
         if (account == null) {
             return null;
         }
+        if (!isUserUnlocked(accounts.userId)) {
+            Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked");
+            return null;
+        }
 
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-            Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
-                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                    new String[]{account.name, account.type}, null, null, null);
-            try {
-                if (cursor.moveToNext()) {
-                    return cursor.getString(0);
-                }
-                return null;
-            } finally {
-                cursor.close();
-            }
+            final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
+            return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
+                    account.type);
         }
     }
 
@@ -699,7 +746,7 @@
                 try {
                     if (cursor.moveToNext()) {
                         String previousName = cursor.getString(0);
-                        previousNameRef = new AtomicReference<String>(previousName);
+                        previousNameRef = new AtomicReference<>(previousName);
                         accounts.previousNameCache.put(account, previousNameRef);
                         return previousName;
                     } else {
@@ -735,7 +782,12 @@
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            return readUserDataInternal(accounts, account, key);
+            synchronized (accounts.cacheLock) {
+                if (!accountExistsCacheLocked(accounts, account)) {
+                    return null;
+                }
+                return readUserDataInternalLocked(accounts, account, key);
+            }
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -825,7 +877,7 @@
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            return addAccountInternal(accounts, account, password, extras, false, callingUid);
+            return addAccountInternal(accounts, account, password, extras, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -999,17 +1051,22 @@
     }
 
     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
-            Bundle extras, boolean restricted, int callingUid) {
+            Bundle extras, int callingUid) {
         Bundle.setDefusable(extras, true);
         if (account == null) {
             return false;
         }
+        if (!isUserUnlocked(accounts.userId)) {
+            Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
+                    + " is locked. callingUid=" + callingUid);
+            return false;
+        }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
                 long numMatches = DatabaseUtils.longForQuery(db,
-                        "select count(*) from " + TABLE_ACCOUNTS
+                        "select count(*) from " + CE_TABLE_ACCOUNTS
                                 + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
                         new String[]{account.name, account.type});
                 if (numMatches > 0) {
@@ -1021,13 +1078,24 @@
                 values.put(ACCOUNTS_NAME, account.name);
                 values.put(ACCOUNTS_TYPE, account.type);
                 values.put(ACCOUNTS_PASSWORD, password);
-                values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
-                long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+                long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
                 if (accountId < 0) {
                     Log.w(TAG, "insertAccountIntoDatabase: " + account
                             + ", skipping the DB insert failed");
                     return false;
                 }
+                // Insert into DE table
+                values = new ContentValues();
+                values.put(ACCOUNTS_ID, accountId);
+                values.put(ACCOUNTS_NAME, account.name);
+                values.put(ACCOUNTS_TYPE, account.type);
+                values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS,
+                        System.currentTimeMillis());
+                if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) {
+                    Log.w(TAG, "insertAccountIntoDatabase: " + account
+                            + ", skipping the DB insert failed");
+                    return false;
+                }
                 if (extras != null) {
                     for (String key : extras.keySet()) {
                         final String value = extras.getString(key);
@@ -1055,6 +1123,12 @@
         return true;
     }
 
+    private boolean isUserUnlocked(int userId) {
+        synchronized (mUsers) {
+            return mUnlockedUsers.get(userId);
+        }
+    }
+
     /**
      * Adds the account to all linked restricted users as shared accounts. If the user is currently
      * running, then clone the account too.
@@ -1079,7 +1153,7 @@
         values.put(EXTRAS_KEY, key);
         values.put(EXTRAS_ACCOUNTS_ID, accountId);
         values.put(EXTRAS_VALUE, value);
-        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+        return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
     }
 
     @Override
@@ -1226,17 +1300,19 @@
             }
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             boolean isSuccessful = false;
             Account renamedAccount = new Account(newName, accountToRename.type);
             try {
-                final ContentValues values = new ContentValues();
-                values.put(ACCOUNTS_NAME, newName);
-                values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
                 final long accountId = getAccountIdLocked(db, accountToRename);
                 if (accountId >= 0) {
+                    final ContentValues values = new ContentValues();
+                    values.put(ACCOUNTS_NAME, newName);
                     final String[] argsAccountId = { String.valueOf(accountId) };
+                    db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+                    // Update NAME/PREVIOUS_NAME in DE accounts table
+                    values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
                     db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                     db.setTransactionSuccessful();
                     isSuccessful = true;
@@ -1332,7 +1408,7 @@
          * authenticator.  This will let users remove accounts (via Settings in the system) but not
          * arbitrary applications (like competing authenticators).
          */
-        UserHandle user = new UserHandle(userId);
+        UserHandle user = UserHandle.of(userId);
         if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
                 && !isSystemUid(callingUid)) {
             String msg = String.format(
@@ -1467,13 +1543,17 @@
     }
 
     private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
+        // For now user is required to be unlocked. TODO: Handle both cases in the future
         int deleted;
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             final long accountId = getAccountIdLocked(db, account);
             deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
                     + "=?",
                     new String[]{account.name, account.type});
+            // Delete from CE table
+            db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                    new String[]{account.name, account.type});
             removeAccountFromCacheLocked(accounts, account);
             sendAccountsChangedBroadcast(accounts.userId);
 
@@ -1512,7 +1592,7 @@
         try {
             UserAccounts accounts = getUserAccounts(userId);
             synchronized (accounts.cacheLock) {
-                final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+                final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
                 db.beginTransaction();
                 try {
                     invalidateAuthTokenLocked(accounts, db, accountType, authToken);
@@ -1544,22 +1624,22 @@
             return;
         }
         Cursor cursor = db.rawQuery(
-                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
-                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
-                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
-                        + " FROM " + TABLE_ACCOUNTS
-                        + " JOIN " + TABLE_AUTHTOKENS
-                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
-                        + " = " + AUTHTOKENS_ACCOUNTS_ID
-                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
-                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+                "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+                        + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+                        + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+                        + " FROM " + CE_TABLE_ACCOUNTS
+                        + " JOIN " + CE_TABLE_AUTHTOKENS
+                        + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+                        + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+                        + " WHERE " + CE_TABLE_AUTHTOKENS + "."  + AUTHTOKENS_AUTHTOKEN
+                        + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
                 new String[]{authToken, accountType});
         try {
             while (cursor.moveToNext()) {
                 long authTokenId = cursor.getLong(0);
                 String accountName = cursor.getString(1);
                 String authTokenType = cursor.getString(2);
-                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+                db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
                 writeAuthTokenIntoCacheLocked(
                         accounts,
                         db,
@@ -1585,7 +1665,7 @@
             return;
         }
         cancelNotification(getSigninRequiredNotificationId(accounts, account),
-                new UserHandle(accounts.userId));
+                UserHandle.of(accounts.userId));
         synchronized (accounts.cacheLock) {
             accounts.accountTokenCaches.put(
                     account, token, tokenType, callerPkg, callerSigDigest, expiryMillis);
@@ -1598,23 +1678,23 @@
             return false;
         }
         cancelNotification(getSigninRequiredNotificationId(accounts, account),
-                new UserHandle(accounts.userId));
+                UserHandle.of(accounts.userId));
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
                 long accountId = getAccountIdLocked(db, account);
                 if (accountId < 0) {
                     return false;
                 }
-                db.delete(TABLE_AUTHTOKENS,
+                db.delete(CE_TABLE_AUTHTOKENS,
                         AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
                         new String[]{type});
                 ContentValues values = new ContentValues();
                 values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
                 values.put(AUTHTOKENS_TYPE, type);
                 values.put(AUTHTOKENS_AUTHTOKEN, authToken);
-                if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+                if (db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
                     db.setTransactionSuccessful();
                     writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
                     return true;
@@ -1714,7 +1794,7 @@
             return;
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
                 final ContentValues values = new ContentValues();
@@ -1722,8 +1802,8 @@
                 final long accountId = getAccountIdLocked(db, account);
                 if (accountId >= 0) {
                     final String[] argsAccountId = {String.valueOf(accountId)};
-                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
-                    db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+                    db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+                    db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
                     accounts.authTokenCache.remove(account);
                     accounts.accountTokenCaches.remove(account);
                     db.setTransactionSuccessful();
@@ -1794,44 +1874,57 @@
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            setUserdataInternal(accounts, account, key, value);
+            synchronized (accounts.cacheLock) {
+                if (!accountExistsCacheLocked(accounts, account)) {
+                    return;
+                }
+                setUserdataInternalLocked(accounts, account, key, value);
+            }
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
-    private void setUserdataInternal(UserAccounts accounts, Account account, String key,
+    private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
+        if (accounts.accountCache.containsKey(account.type)) {
+            for (Account acc : accounts.accountCache.get(account.type)) {
+                if (acc.name.equals(account.name)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
             String value) {
         if (account == null || key == null) {
             return;
         }
-        synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-            db.beginTransaction();
-            try {
-                long accountId = getAccountIdLocked(db, account);
-                if (accountId < 0) {
+        final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            long accountId = getAccountIdLocked(db, account);
+            if (accountId < 0) {
+                return;
+            }
+            long extrasId = getExtrasIdLocked(db, accountId, key);
+            if (extrasId < 0) {
+                extrasId = insertExtraLocked(db, accountId, key, value);
+                if (extrasId < 0) {
                     return;
                 }
-                long extrasId = getExtrasIdLocked(db, accountId, key);
-                if (extrasId < 0 ) {
-                    extrasId = insertExtraLocked(db, accountId, key, value);
-                    if (extrasId < 0) {
-                        return;
-                    }
-                } else {
-                    ContentValues values = new ContentValues();
-                    values.put(EXTRAS_VALUE, value);
-                    if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
-                        return;
-                    }
-
+            } else {
+                ContentValues values = new ContentValues();
+                values.put(EXTRAS_VALUE, value);
+                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+                    return;
                 }
-                writeUserDataIntoCacheLocked(accounts, db, account, key, value);
-                db.setTransactionSuccessful();
-            } finally {
-                db.endTransaction();
             }
+            writeUserDataIntoCacheLocked(accounts, db, account, key, value);
+            db.setTransactionSuccessful();
+        } finally {
+            db.endTransaction();
         }
     }
 
@@ -2425,21 +2518,31 @@
                     userId);
             return;
         }
-
         final int pid = Binder.getCallingPid();
         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
         options.putInt(AccountManager.KEY_CALLER_UID, uid);
         options.putInt(AccountManager.KEY_CALLER_PID, pid);
 
+        // Check to see if the Password should be included to the caller.
+        String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+        boolean isPasswordForwardingAllowed = isPermitted(
+                callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
         int usrId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(usrId);
             logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
                     TABLE_ACCOUNTS, uid);
-            new StartAccountSession(accounts, response, accountType, expectActivityLaunch,
-                    null /* accountName */, false /* authDetailsRequired */,
-                    true /* updateLastAuthenticationTime */) {
+            new StartAccountSession(
+                    accounts,
+                    response,
+                    accountType,
+                    expectActivityLaunch,
+                    null /* accountName */,
+                    false /* authDetailsRequired */,
+                    true /* updateLastAuthenticationTime */,
+                    isPasswordForwardingAllowed) {
                 @Override
                 public void run() throws RemoteException {
                     mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
@@ -2462,12 +2565,21 @@
     /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
     private abstract class StartAccountSession extends Session {
 
-        public StartAccountSession(UserAccounts accounts, IAccountManagerResponse response,
-                String accountType, boolean expectActivityLaunch, String accountName,
-                boolean authDetailsRequired, boolean updateLastAuthenticationTime) {
+        private final boolean mIsPasswordForwardingAllowed;
+
+        public StartAccountSession(
+                UserAccounts accounts,
+                IAccountManagerResponse response,
+                String accountType,
+                boolean expectActivityLaunch,
+                String accountName,
+                boolean authDetailsRequired,
+                boolean updateLastAuthenticationTime,
+                boolean isPasswordForwardingAllowed) {
             super(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
                     updateLastAuthenticationTime);
+            mIsPasswordForwardingAllowed = isPasswordForwardingAllowed;
         }
 
         @Override
@@ -2480,6 +2592,10 @@
                 checkKeyIntent(
                         Binder.getCallingUid(),
                         intent);
+                // Omit passwords if the caller isn't permitted to see them.
+                if (!mIsPasswordForwardingAllowed) {
+                    result.remove(AccountManager.KEY_PASSWORD);
+                }
             }
             IAccountManagerResponse response;
             if (mExpectActivityLaunch && result != null
@@ -2826,6 +2942,12 @@
         }
 
         int userId = UserHandle.getCallingUserId();
+
+        // Check to see if the Password should be included to the caller.
+        String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+        boolean isPasswordForwardingAllowed = isPermitted(
+                callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -2836,7 +2958,8 @@
                     expectActivityLaunch,
                     account.name,
                     false /* authDetailsRequired */,
-                    true /* updateLastCredentialTime */) {
+                    true /* updateLastCredentialTime */,
+                    isPasswordForwardingAllowed) {
                 @Override
                 public void run() throws RemoteException {
                     mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType,
@@ -3307,7 +3430,6 @@
         long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
         final ContentValues values = new ContentValues();
         values.put(ACCOUNTS_NAME, newName);
-        values.put(ACCOUNTS_PREVIOUS_NAME, account.name);
         int r = db.update(
                 TABLE_SHARED_ACCOUNTS,
                 values,
@@ -3347,7 +3469,7 @@
     public Account[] getSharedAccountsAsUser(int userId) {
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
-        ArrayList<Account> accountList = new ArrayList<Account>();
+        ArrayList<Account> accountList = new ArrayList<>();
         Cursor cursor = null;
         try {
             cursor = accounts.openHelper.getReadableDatabase()
@@ -3488,7 +3610,7 @@
     }
 
     private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
-        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+        Cursor cursor = db.query(CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
                 EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
                 new String[]{key}, null, null, null);
         try {
@@ -3729,8 +3851,8 @@
                         if (accountPresent) {
                             lastAuthenticatedTime = DatabaseUtils.longForQuery(
                                     mAccounts.openHelper.getReadableDatabase(),
-                                    "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
-                                            + " from " +
+                                    "SELECT " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                                            + " FROM " +
                                             TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
                                             + ACCOUNTS_TYPE + "=?",
                                     new String[] {
@@ -3859,7 +3981,7 @@
                 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
             }
             if (!mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
-                    new UserHandle(mAccounts.userId))) {
+                    UserHandle.of(mAccounts.userId))) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
                 }
@@ -3893,15 +4015,16 @@
         }
     }
 
-    private static String getDatabaseName(int userId) {
+    static String getPreNDatabaseName(int userId) {
         File systemDir = Environment.getDataSystemDirectory();
-        File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
+        File databaseFile = new File(Environment.getUserSystemDirectory(userId),
+                PRE_N_DATABASE_NAME);
         if (userId == 0) {
             // Migrate old file, if it exists, to the new location.
             // Make sure the new file doesn't already exist. A dummy file could have been
             // accidentally created in the old location, causing the new one to become corrupted
             // as well.
-            File oldFile = new File(systemDir, DATABASE_NAME);
+            File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
             if (oldFile.exists() && !databaseFile.exists()) {
                 // Check for use directory; create if it doesn't exist, else renameTo will fail
                 File userDir = Environment.getUserSystemDirectory(userId);
@@ -3918,6 +4041,18 @@
         return databaseFile.getPath();
     }
 
+    static String getDeDatabaseName(int userId) {
+        File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
+                DE_DATABASE_NAME);
+        return databaseFile.getPath();
+    }
+
+    static String getCeDatabaseName(int userId) {
+        File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
+                CE_DATABASE_NAME);
+        return databaseFile.getPath();
+    }
+
     private static class DebugDbHelper{
         private DebugDbHelper() {
         }
@@ -4050,58 +4185,22 @@
         return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
     }
 
-    static class DatabaseHelper extends SQLiteOpenHelper {
+    static class PreNDatabaseHelper extends SQLiteOpenHelper {
 
         private final Context mContext;
         private final int mUserId;
 
-        public DatabaseHelper(Context context, int userId) {
-            super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
+        public PreNDatabaseHelper(Context context, int userId) {
+            super(context, AccountManagerService.getPreNDatabaseName(userId), null,
+                    PRE_N_DATABASE_VERSION);
             mContext = context;
             mUserId = userId;
         }
 
-        /**
-         * This call needs to be made while the mCacheLock is held. The way to
-         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
-         * @param db The database.
-         */
         @Override
         public void onCreate(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
-                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
-                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
-                    + ACCOUNTS_PASSWORD + " TEXT, "
-                    + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
-                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
-                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
-                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
-                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
-                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
-                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
-                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
-
-            createGrantsTable(db);
-
-            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
-                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
-                    + EXTRAS_KEY + " TEXT NOT NULL, "
-                    + EXTRAS_VALUE + " TEXT, "
-                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
-                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
-                    + META_VALUE + " TEXT)");
-
-            createSharedAccountsTable(db);
-
-            createAccountsDeletionTrigger(db);
-
-            DebugDbHelper.createDebugTable(db);
+            // We use PreNDatabaseHelper only if pre-N db exists
+            throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
         }
 
         private void createSharedAccountsTable(SQLiteDatabase db) {
@@ -4161,6 +4260,9 @@
             }
         }
 
+        /**
+         * Pre-N database may need an upgrade before splitting
+         */
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
@@ -4222,6 +4324,315 @@
         }
     }
 
+    static class DeDatabaseHelper extends SQLiteOpenHelper {
+
+        private final int mUserId;
+        private volatile boolean mCeAttached;
+
+        private DeDatabaseHelper(Context context, int userId) {
+            super(context, getDeDatabaseName(userId), null, DE_DATABASE_VERSION);
+            mUserId = userId;
+        }
+
+        /**
+         * This call needs to be made while the mCacheLock is held. The way to
+         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+         * @param db The database.
+         */
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.i(TAG, "Creating DE database for user " + mUserId);
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+                    + META_VALUE + " TEXT)");
+
+            createGrantsTable(db);
+            createSharedAccountsTable(db);
+            createAccountsDeletionTrigger(db);
+            DebugDbHelper.createDebugTable(db);
+        }
+
+        private void createSharedAccountsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_GRANTS
+                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        private void createGrantsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
+                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
+                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
+                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+                    +   "," + GRANTS_GRANTEE_UID + "))");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        public void attachCeDatabase() {
+            File ceDbFile = new File(getCeDatabaseName(mUserId));
+            SQLiteDatabase db = getWritableDatabase();
+            db.execSQL("ATTACH DATABASE '" +  ceDbFile.getPath()+ "' AS ceDb");
+            mCeAttached = true;
+        }
+
+        public boolean isCeDatabaseAttached() {
+            return mCeAttached;
+        }
+
+
+        public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
+            if(!mCeAttached) {
+                Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user "
+                        + mUserId + " is still locked ", new Throwable());
+            }
+            return super.getReadableDatabase();
+        }
+
+        public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
+            if(!mCeAttached) {
+                Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
+                        + " is still locked ", new Throwable());
+            }
+            return super.getWritableDatabase();
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
+        }
+
+        private void migratePreNDbToDe(File preNDbFile) {
+            Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
+            SQLiteDatabase db = getWritableDatabase();
+            db.execSQL("ATTACH DATABASE '" +  preNDbFile.getPath() + "' AS preNDb");
+            db.beginTransaction();
+            // Copy accounts fields
+            db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
+                    + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                    + ") "
+                    + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                    + " FROM preNDb." + TABLE_ACCOUNTS);
+            // Copy SHARED_ACCOUNTS
+            db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
+                    + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
+                    "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+                    + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
+            // Copy DEBUG_TABLE
+            db.execSQL("INSERT INTO " + DebugDbHelper.TABLE_DEBUG
+                    + "(" + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+                    + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+                    + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY + ") " +
+                    "SELECT " + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
+                    + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
+                    + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY
+                    + " FROM preNDb." + DebugDbHelper.TABLE_DEBUG);
+            // Copy GRANTS
+            db.execSQL("INSERT INTO " + TABLE_GRANTS
+                    + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+                    + GRANTS_GRANTEE_UID + ") " +
+                    "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+                    + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
+            // Copy META
+            db.execSQL("INSERT INTO " + TABLE_META
+                    + "(" + META_KEY + "," + META_VALUE + ") "
+                    + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
+            db.setTransactionSuccessful();
+            db.endTransaction();
+
+            db.execSQL("DETACH DATABASE preNDb");
+        }
+
+        static DeDatabaseHelper create(Context context, int userId) {
+            File oldDb = new File(getPreNDatabaseName(userId));
+            File newDb = new File(getDeDatabaseName(userId));
+            boolean newDbExists = newDb.exists();
+            DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId);
+            // If the db just created, and there is a legacy db, migrate it
+            if (!newDbExists && oldDb.exists()) {
+                // Migrate legacy db to the latest version -  PRE_N_DATABASE_VERSION
+                PreNDatabaseHelper preNDatabaseHelper = new PreNDatabaseHelper(context, userId);
+                // Open the database to force upgrade if required
+                preNDatabaseHelper.getWritableDatabase();
+                preNDatabaseHelper.close();
+                // Move data without SPII to DE
+                deDatabaseHelper.migratePreNDbToDe(oldDb);
+            }
+            return deDatabaseHelper;
+        }
+    }
+
+    static class CeDatabaseHelper extends SQLiteOpenHelper {
+
+        public CeDatabaseHelper(Context context, int userId) {
+            super(context, getCeDatabaseName(userId), null, CE_DATABASE_VERSION);
+        }
+
+        /**
+         * This call needs to be made while the mCacheLock is held.
+         * @param db The database.
+         */
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.i(TAG, "Creating CE database " + getDatabaseName());
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PASSWORD + " TEXT, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
+                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
+                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
+                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
+                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+                    + EXTRAS_KEY + " TEXT NOT NULL, "
+                    + EXTRAS_VALUE + " TEXT, "
+                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+            createAccountsDeletionTrigger(db);
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_AUTHTOKENS
+                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + "   DELETE FROM " + TABLE_EXTRAS
+                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion == 9) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "onUpgrade upgrading to v10");
+                }
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
+                // Recreate the trigger, since the old one references the table to be removed
+                db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
+                createAccountsDeletionTrigger(db);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
+                db.execSQL("DROP TABLE IF EXISTS " + DebugDbHelper.TABLE_DEBUG);
+                oldVersion ++;
+            }
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
+        }
+
+        static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
+                String type) {
+            Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                    new String[]{name, type}, null, null, null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getString(0);
+                }
+                return null;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        /**
+         * Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
+         * it also performs migration to the new CE database.
+         * @param context
+         * @param userId id of the user where the database is located
+         */
+        static CeDatabaseHelper create(Context context, int userId) {
+
+            File oldDatabaseFile = new File(getPreNDatabaseName(userId));
+            File ceDatabaseFile = new File(getCeDatabaseName(userId));
+            boolean newDbExists = ceDatabaseFile.exists();
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
+                        + oldDatabaseFile.exists() + " newDbExists=" + newDbExists);
+            }
+            boolean removeOldDb = false;
+            if (!newDbExists && oldDatabaseFile.exists()) {
+                removeOldDb = migratePreNDbToCe(oldDatabaseFile, ceDatabaseFile);
+            }
+            // Try to open and upgrade if necessary
+            CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, userId);
+            ceHelper.getWritableDatabase();
+            ceHelper.close();
+            if (removeOldDb) {
+                // TODO STOPSHIP - backup file during testing. Remove file before the release
+                Log.i(TAG, "Migration complete - creating backup of old db " + oldDatabaseFile);
+                renameToBakFile(oldDatabaseFile);
+            }
+            return ceHelper;
+        }
+
+        private static void renameToBakFile(File file) {
+            File bakFile = new File(file.getPath() + ".bak");
+            if (!file.renameTo(bakFile)) {
+                Log.e(TAG, "Cannot move file to " + bakFile);
+            }
+        }
+
+        private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
+            Log.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+            try {
+                FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
+            } catch (IOException e) {
+                Log.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+                // Try to remove potentially damaged file if I/O error occurred
+                deleteDbFileWarnIfFailed(ceDbFile);
+                return false;
+            }
+            return true;
+        }
+    }
+
     public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
         return asBinder();
     }
@@ -4666,7 +5077,7 @@
                 db.endTransaction();
             }
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
-                    new UserHandle(accounts.userId));
+                    UserHandle.of(accounts.userId));
         }
     }
 
@@ -4891,7 +5302,7 @@
             HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
             if (authTokensForAccount == null) {
                 // need to populate the cache for this account
-                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+                final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
                 authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
                 accounts.authTokenCache.put(account, authTokensForAccount);
             }
@@ -4899,23 +5310,22 @@
         }
     }
 
-    protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
-        synchronized (accounts.cacheLock) {
-            HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
-            if (userDataForAccount == null) {
-                // need to populate the cache for this account
-                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-                userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
-                accounts.userDataCache.put(account, userDataForAccount);
-            }
-            return userDataForAccount.get(key);
+    protected String readUserDataInternalLocked(
+            UserAccounts accounts, Account account, String key) {
+        HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+        if (userDataForAccount == null) {
+            // need to populate the cache for this account
+            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+            userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+            accounts.userDataCache.put(account, userDataForAccount);
         }
+        return userDataForAccount.get(key);
     }
 
     protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
             final SQLiteDatabase db, Account account) {
-        HashMap<String, String> userDataForAccount = new HashMap<String, String>();
-        Cursor cursor = db.query(TABLE_EXTRAS,
+        HashMap<String, String> userDataForAccount = new HashMap<>();
+        Cursor cursor = db.query(CE_TABLE_EXTRAS,
                 COLUMNS_EXTRAS_KEY_AND_VALUE,
                 SELECTION_USERDATA_BY_ACCOUNT,
                 new String[]{account.name, account.type},
@@ -4934,8 +5344,8 @@
 
     protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
             final SQLiteDatabase db, Account account) {
-        HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
-        Cursor cursor = db.query(TABLE_AUTHTOKENS,
+        HashMap<String, String> authTokensForAccount = new HashMap<>();
+        Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
                 COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
                 SELECTION_AUTHTOKENS_BY_ACCOUNT,
                 new String[]{account.name, account.type},
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f99caba..d741c49 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -940,7 +940,7 @@
                 }
             }
 
-            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
+            mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
                     s.appInfo.uid, s.name, s.processName);
 
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4bb3a54..1da6a20 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -351,7 +351,6 @@
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
-import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
@@ -892,6 +891,12 @@
         int mNesting;
         long mStartTime;
 
+        // states of the source process when the bind occurred.
+        int mLastState = ActivityManager.MAX_PROCESS_STATE + 1;
+        long mLastStateUptime;
+        long[] mStateTimes = new long[ActivityManager.MAX_PROCESS_STATE
+                - ActivityManager.MIN_PROCESS_STATE+1];
+
         Association(int sourceUid, String sourceProcess, int targetUid,
                 ComponentName targetComponent, String targetProcess) {
             mSourceUid = sourceUid;
@@ -1100,20 +1105,20 @@
     ComponentName mTopComponent;
     String mTopAction = Intent.ACTION_MAIN;
     String mTopData;
-    boolean mProcessesReady = false;
-    boolean mSystemReady = false;
-    boolean mBooting = false;
-    boolean mCallFinishBooting = false;
-    boolean mBootAnimationComplete = false;
-    boolean mOnBattery = false;
-    boolean mLaunchWarningShown = false;
+
+    volatile boolean mProcessesReady = false;
+    volatile boolean mSystemReady = false;
+    volatile boolean mOnBattery = false;
+    volatile int mFactoryTest;
+
+    @GuardedBy("this") boolean mBooting = false;
+    @GuardedBy("this") boolean mCallFinishBooting = false;
+    @GuardedBy("this") boolean mBootAnimationComplete = false;
+    @GuardedBy("this") boolean mLaunchWarningShown = false;
+    @GuardedBy("this") boolean mCheckedForSetup = false;
 
     Context mContext;
 
-    int mFactoryTest;
-
-    boolean mCheckedForSetup;
-
     /**
      * The time at which we will allow normal application switches again,
      * after a call to {@link #stopAppSwitches()}.
@@ -6057,8 +6062,7 @@
                         "No more processes in " + old.uidRecord);
                 enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
                 mActiveUids.remove(uid);
-                mBatteryStatsService.noteUidProcessState(uid,
-                        ActivityManager.PROCESS_STATE_NONEXISTENT);
+                noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
             }
             old.uidRecord = null;
         }
@@ -6083,7 +6087,7 @@
             if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                     "Creating new process uid: " + uidRec);
             mActiveUids.put(proc.uid, uidRec);
-            mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+            noteUidProcessState(uidRec.uid, uidRec.curProcState);
             enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
         }
         proc.uidRecord = uidRec;
@@ -7231,7 +7235,7 @@
     }
 
     @Override
-    public boolean inMultiWindow(IBinder token) {
+    public boolean isInMultiWindowMode(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
@@ -7248,7 +7252,7 @@
     }
 
     @Override
-    public boolean inPictureInPicture(IBinder token) {
+    public boolean isInPictureInPictureMode(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
@@ -7264,24 +7268,24 @@
     }
 
     @Override
-    public void enterPictureInPicture(IBinder token) {
+    public void enterPictureInPictureMode(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
                 if (!mSupportsPictureInPicture) {
-                    throw new IllegalStateException("enterPictureInPicture: "
+                    throw new IllegalStateException("enterPictureInPictureMode: "
                             + "Device doesn't support picture-in-picture mode.");
                 }
 
                 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
 
                 if (r == null) {
-                    throw new IllegalStateException("enterPictureInPicture: "
+                    throw new IllegalStateException("enterPictureInPictureMode: "
                             + "Can't find activity for token=" + token);
                 }
 
                 if (!r.supportsPictureInPicture()) {
-                    throw new IllegalArgumentException("enterPictureInPicture: "
+                    throw new IllegalArgumentException("enterPictureInPictureMode: "
                             + "Picture-In-Picture not supported for r=" + r);
                 }
 
@@ -7290,7 +7294,7 @@
                         ? mDefaultPinnedStackBounds : null;
 
                 mStackSupervisor.moveActivityToPinnedStackLocked(
-                        r, "enterPictureInPicture", bounds);
+                        r, "enterPictureInPictureMode", bounds);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -9823,7 +9827,8 @@
     public void updateLockTaskPackages(int userId, String[] packages) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
-            throw new SecurityException("updateLockTaskPackage called from non-system process");
+            enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+                    "updateLockTaskPackages()");
         }
         synchronized (this) {
             if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
@@ -10191,7 +10196,8 @@
             }
             cpr.connections.add(conn);
             r.conProviders.add(conn);
-            startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);
+            startAssociationLocked(r.uid, r.processName, r.curProcState,
+                    cpr.uid, cpr.name, cpr.info.processName);
             return conn;
         }
         cpr.addExternalProcessHandleLocked(externalProcessToken);
@@ -13798,10 +13804,27 @@
                         TimeUtils.formatDuration(dur, pw);
                         pw.print(" (");
                         pw.print(ass.mCount);
-                        pw.println(" times)");
+                        pw.print(" times)");
+                        pw.print("  ");
+                        for (int i=0; i<ass.mStateTimes.length; i++) {
+                            long amt = ass.mStateTimes[i];
+                            if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+                                amt += now - ass.mLastStateUptime;
+                            }
+                            if (amt != 0) {
+                                pw.print(" ");
+                                pw.print(ProcessList.makeProcStateString(
+                                            i + ActivityManager.MIN_PROCESS_STATE));
+                                pw.print("=");
+                                TimeUtils.formatDuration(amt, pw);
+                                if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+                                    pw.print("*");
+                                }
+                            }
+                        }
+                        pw.println();
                         if (ass.mNesting > 0) {
-                            pw.print("    ");
-                            pw.print(" Currently active: ");
+                            pw.print("    Currently active: ");
                             TimeUtils.formatDuration(now - ass.mStartTime, pw);
                             pw.println();
                         }
@@ -18022,6 +18045,9 @@
             ActivityRecord starting, boolean initLocale, boolean persistent, int userId) {
         int changes = 0;
 
+        if (mWindowManager != null) {
+            mWindowManager.deferSurfaceLayout();
+        }
         if (values != null) {
             Configuration newConfig = new Configuration(mConfiguration);
             changes = newConfig.updateFrom(values);
@@ -18122,6 +18148,20 @@
                             null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
                 }
             }
+            // Update the configuration with WM first and check if any of the stacks need to be
+            // resized due to the configuration change. If so, resize the stacks now and do any
+            // relaunches if necessary. This way we don't need to relaunch again below in
+            // ensureActivityConfigurationLocked().
+            if (mWindowManager != null) {
+                final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
+                if (resizedStacks != null) {
+                    for (int stackId : resizedStacks) {
+                        final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+                        mStackSupervisor.resizeStackLocked(
+                                stackId, newBounds, null, null, false, false);
+                    }
+                }
+            }
         }
 
         boolean kept = true;
@@ -18143,11 +18183,9 @@
                         !PRESERVE_WINDOWS);
             }
         }
-
-        if (values != null && mWindowManager != null) {
-            mWindowManager.setNewConfiguration(mConfiguration);
+        if (mWindowManager != null) {
+            mWindowManager.continueSurfaceLayout();
         }
-
         return kept;
     }
 
@@ -18239,8 +18277,8 @@
         return null;
     }
 
-    Association startAssociationLocked(int sourceUid, String sourceProcess, int targetUid,
-            ComponentName targetComponent, String targetProcess) {
+    Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
+            int targetUid, ComponentName targetComponent, String targetProcess) {
         if (!mTrackingAssociations) {
             return null;
         }
@@ -18269,7 +18307,8 @@
         ass.mCount++;
         ass.mNesting++;
         if (ass.mNesting == 1) {
-            ass.mStartTime = SystemClock.uptimeMillis();
+            ass.mStartTime = ass.mLastStateUptime = SystemClock.uptimeMillis();
+            ass.mLastState = sourceState;
         }
         return ass;
     }
@@ -18298,7 +18337,39 @@
         }
         ass.mNesting--;
         if (ass.mNesting == 0) {
-            ass.mTime += SystemClock.uptimeMillis() - ass.mStartTime;
+            long uptime = SystemClock.uptimeMillis();
+            ass.mTime += uptime - ass.mStartTime;
+            ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+                    += uptime - ass.mLastStateUptime;
+            ass.mLastState = ActivityManager.MAX_PROCESS_STATE + 2;
+        }
+    }
+
+    private void noteUidProcessState(final int uid, final int state) {
+        mBatteryStatsService.noteUidProcessState(uid, state);
+        if (mTrackingAssociations) {
+            for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
+                ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
+                        = mAssociations.valueAt(i1);
+                for (int i2=0, N2=targetComponents.size(); i2<N2; i2++) {
+                    SparseArray<ArrayMap<String, Association>> sourceUids
+                            = targetComponents.valueAt(i2);
+                    ArrayMap<String, Association> sourceProcesses = sourceUids.get(uid);
+                    if (sourceProcesses != null) {
+                        for (int i4=0, N4=sourceProcesses.size(); i4<N4; i4++) {
+                            Association ass = sourceProcesses.valueAt(i4);
+                            if (ass.mNesting >= 1) {
+                                // currently associated
+                                long uptime = SystemClock.uptimeMillis();
+                                ass.mStateTimes[ass.mLastState-ActivityManager.MIN_PROCESS_STATE]
+                                        += uptime - ass.mLastStateUptime;
+                                ass.mLastState = state;
+                                ass.mLastStateUptime = uptime;
+                            }
+                        }
+                    }
+                }
+            }
         }
     }
 
@@ -20177,7 +20248,7 @@
                 }
                 uidRec.setProcState = uidRec.curProcState;
                 enqueueUidChangeLocked(uidRec, -1, uidChange);
-                mBatteryStatsService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+                noteUidProcessState(uidRec.uid, uidRec.curProcState);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d570be9..9be6b43 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -23,8 +23,6 @@
 import android.os.UserHandle;
 import android.util.DebugUtils;
 
-import com.android.internal.util.ArrayUtils;
-
 import java.io.PrintWriter;
 
 class ActivityManagerShellCommand extends ShellCommand {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5219827..48f87b6 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -23,7 +23,6 @@
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
@@ -452,24 +451,24 @@
         }
     }
 
-    void scheduleMultiWindowChanged() {
+    void scheduleMultiWindowModeChanged() {
         if (task == null || task.stack == null || app == null || app.thread == null) {
             return;
         }
         try {
             // An activity is considered to be in multi-window mode if its task isn't fullscreen.
-            app.thread.scheduleMultiWindowChanged(appToken, !task.mFullscreen);
+            app.thread.scheduleMultiWindowModeChanged(appToken, !task.mFullscreen);
         } catch (Exception e) {
             // If process died, I don't care.
         }
     }
 
-    void schedulePictureInPictureChanged() {
+    void schedulePictureInPictureModeChanged() {
         if (task == null || task.stack == null || app == null || app.thread == null) {
             return;
         }
         try {
-            app.thread.schedulePictureInPictureChanged(
+            app.thread.schedulePictureInPictureModeChanged(
                     appToken, task.stack.mStackId == PINNED_STACK_ID);
         } catch (Exception e) {
             // If process died, no one cares.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a9ef1d6..4ec1f61 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4574,6 +4574,8 @@
         }
 
         r.configChangeFlags = 0;
+        r.deferRelaunchUntilPaused = false;
+        r.preserveWindowOnDeferredRelaunch = false;
     }
 
     boolean willActivityBeVisibleLocked(IBinder token) {
@@ -4986,7 +4988,7 @@
 
     private void postAddTask(TaskRecord task, ActivityStack prevStack) {
         if (prevStack != null) {
-            mStackSupervisor.scheduleReportPictureInPictureChangedIfNeeded(task, prevStack);
+            mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
         } else if (task.voiceSession != null) {
             try {
                 task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -5045,7 +5047,7 @@
         r.setTask(task, null);
         task.addActivityToTop(r);
         setAppTask(r, task);
-        mStackSupervisor.scheduleReportPictureInPictureChangedIfNeeded(task, prevStack);
+        mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
         moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
         if (wasResumed) {
             prevStack.mResumedActivity = null;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 950320e..6c09178 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -102,7 +102,6 @@
 import java.util.Objects;
 import java.util.Set;
 
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.START_ANY_ACTIVITY;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
@@ -2070,14 +2069,16 @@
                 // static stacks need to be adjusted so they don't overlap with the docked stack.
                 // We get the bounds to use from window manager which has been adjusted for any
                 // screen controls and is also the same for all stacks.
-                mWindowManager.getStackDockedModeBounds(
-                        HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+                if (dockedBounds != null) {
+                    mWindowManager.getStackDockedModeBounds(
+                            HOME_STACK_ID, tempRect, true /* ignoreVisibility */);
+                }
                 for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
                     if (StackId.isResizeableByDockedStack(i)) {
                         ActivityStack otherStack = getStack(i);
                         if (otherStack != null) {
-                            resizeStackLocked(i, tempRect, tempOtherTaskBounds,
-                                    tempOtherTaskInsetBounds, preserveWindows,
+                            resizeStackLocked(i, dockedBounds != null ? tempRect : null,
+                                    tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows,
                                     true /* allowResizeInDockedMode */);
                         }
                     }
@@ -2739,12 +2740,21 @@
 
     // Called when WindowManager has finished animating the launchingBehind activity to the back.
     void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
-        r.mLaunchTaskBehind = false;
         final TaskRecord task = r.task;
-        task.setLastThumbnailLocked(task.stack.screenshotActivitiesLocked(r));
+        final ActivityStack stack = task.stack;
+
+        r.mLaunchTaskBehind = false;
+        task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
         mRecentTasks.addLocked(task);
         mService.notifyTaskStackChangedLocked();
         mWindowManager.setAppVisibility(r.appToken, false);
+
+        // When launching tasks behind, update the last active time of the top task after the new
+        // task has been shown briefly
+        final ActivityRecord top = stack.topActivity();
+        if (top != null) {
+            top.task.touchActiveTime();
+        }
     }
 
     void scheduleLaunchTaskBehindComplete(IBinder token) {
@@ -3524,7 +3534,7 @@
         mActivityMetricsLogger.logWindowState();
     }
 
-    void scheduleReportMultiWindowChanged(TaskRecord task) {
+    void scheduleReportMultiWindowModeChanged(TaskRecord task) {
         for (int i = task.mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = task.mActivities.get(i);
             if (r.app != null && r.app.thread != null) {
@@ -3537,7 +3547,7 @@
         }
     }
 
-    void scheduleReportPictureInPictureChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
+    void scheduleReportPictureInPictureModeChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
         final ActivityStack stack = task.stack;
         if (prevStack == null || prevStack == stack
                 || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
@@ -3575,7 +3585,7 @@
                     synchronized (mService) {
                         for (int i = mMultiWindowModeChangedActivities.size() - 1; i >= 0; i--) {
                             final ActivityRecord r = mMultiWindowModeChangedActivities.remove(i);
-                            r.scheduleMultiWindowChanged();
+                            r.scheduleMultiWindowModeChanged();
                         }
                     }
                 } break;
@@ -3583,7 +3593,7 @@
                     synchronized (mService) {
                         for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
                             final ActivityRecord r = mPipModeChangedActivities.remove(i);
-                            r.schedulePictureInPictureChanged();
+                            r.schedulePictureInPictureModeChanged();
                         }
                     }
                 } break;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 0f1ebeb..e32d1d1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -285,6 +285,7 @@
         mCallingPackage = info.packageName;
         setIntent(_intent, info);
         setMinDimensions(info);
+        touchActiveTime();
     }
 
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
@@ -315,6 +316,7 @@
         taskType = APPLICATION_ACTIVITY_TYPE;
         mTaskToReturnTo = HOME_ACTIVITY_TYPE;
         lastTaskDescription = _taskDescription;
+        touchActiveTime();
     }
 
     private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
@@ -1449,7 +1451,7 @@
         }
 
         if (mFullscreen != oldFullscreen) {
-            mService.mStackSupervisor.scheduleReportMultiWindowChanged(this);
+            mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
         }
 
         return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c59591e9..aef454e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -434,35 +434,17 @@
                 stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                 stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
-                final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
-                // This is the result receiver for the final shutdown broadcast.
-                final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
-                    @Override
-                    public void performReceive(Intent intent, int resultCode, String data,
-                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                        finishUserStop(uss);
-                    }
-                };
                 // This is the result receiver for the initial stopping broadcast.
                 final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
                     @Override
                     public void performReceive(Intent intent, int resultCode, String data,
                             Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                        // On to the next.
-                        synchronized (mService) {
-                            if (uss.state != UserState.STATE_STOPPING) {
-                                // Whoops, we are being started back up.  Abort, abort!
-                                return;
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                finishUserStopping(userId, uss);
                             }
-                            uss.setState(UserState.STATE_SHUTDOWN);
-                        }
-                        mService.mBatteryStatsService.noteEvent(
-                                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
-                                Integer.toString(userId), userId);
-                        mService.mSystemServiceManager.stopUser(userId);
-                        mService.broadcastIntentLocked(null, null, shutdownIntent,
-                                null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, MY_PID, SYSTEM_UID, userId);
+                        });
                     }
                 };
                 // Kick things off.
@@ -476,7 +458,45 @@
         }
     }
 
-    void finishUserStop(UserState uss) {
+    void finishUserStopping(final int userId, final UserState uss) {
+        // On to the next.
+        final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+        // This is the result receiver for the final shutdown broadcast.
+        final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
+            @Override
+            public void performReceive(Intent intent, int resultCode, String data,
+                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        finishUserStopped(uss);
+                    }
+                });
+            }
+        };
+
+        synchronized (mService) {
+            if (uss.state != UserState.STATE_STOPPING) {
+                // Whoops, we are being started back up.  Abort, abort!
+                return;
+            }
+            uss.setState(UserState.STATE_SHUTDOWN);
+        }
+
+        mService.mBatteryStatsService.noteEvent(
+                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
+                Integer.toString(userId), userId);
+        mService.mSystemServiceManager.stopUser(userId);
+
+        synchronized (mService) {
+            mService.broadcastIntentLocked(null, null, shutdownIntent,
+                    null, shutdownReceiver, 0, null, null, null,
+                    AppOpsManager.OP_NONE,
+                    null, true, false, MY_PID, SYSTEM_UID, userId);
+        }
+    }
+
+    void finishUserStopped(UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
         boolean stopped;
         ArrayList<IStopUserCallback> callbacks;
@@ -765,10 +785,17 @@
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         mService.broadcastIntentLocked(null, null, intent, null,
                                 new IIntentReceiver.Stub() {
+                                    @Override
                                     public void performReceive(Intent intent, int resultCode,
                                             String data, Bundle extras, boolean ordered,
                                             boolean sticky, int sendingUser) {
-                                        onUserInitialized(uss, foreground, oldUserId, userId);
+                                        mHandler.post(new Runnable() {
+                                            @Override
+                                            public void run() {
+                                                onUserInitialized(uss, foreground,
+                                                        oldUserId, userId);
+                                            }
+                                        });
                                     }
                                 }, 0, null, null, null, AppOpsManager.OP_NONE,
                                 null, true, false, MY_PID, SYSTEM_UID, userId);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 28170f2..7f7ea9d 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -26,9 +26,9 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IContentService;
+import android.content.ISyncStatusObserver;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ISyncStatusObserver;
 import android.content.PeriodicSync;
 import android.content.SyncAdapterType;
 import android.content.SyncInfo;
@@ -58,18 +58,15 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.security.InvalidParameterException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Objects;
 
 /**
  * {@hide}
@@ -1030,14 +1027,16 @@
 
         if (uri != null) {
             for (int i = 0; i < packageCache.size();) {
-                final Uri key = packageCache.keyAt(i).second;
-                if (Objects.equals(key, uri)) {
+                final Pair<String, Uri> key = packageCache.keyAt(i);
+                if (key.second != null && key.second.toString().startsWith(uri.toString())) {
+                    Slog.d(TAG, "Invalidating cache for key " + key);
                     packageCache.removeAt(i);
                 } else {
                     i++;
                 }
             }
         } else {
+            Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
             packageCache.clear();
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1ed7070..8f8afd5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -103,7 +103,6 @@
     private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
 
     // Brightness animation ramp rate in brightness units per second.
-    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
     private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
 
     private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
@@ -244,6 +243,9 @@
     private boolean mAppliedDimming;
     private boolean mAppliedLowPower;
 
+    // Brightness ramp rate fast.
+    private final int mBrightnessRampRateFast;
+
     // The controller for the automatic brightness level.
     private AutomaticBrightnessController mAutomaticBrightnessController;
 
@@ -303,6 +305,9 @@
         mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
 
+        mBrightnessRampRateFast = resources.getInteger(
+                com.android.internal.R.integer.config_brightness_ramp_rate_fast);
+
         int lightSensorRate = resources.getInteger(
                 com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
         long brighteningLightDebounce = resources.getInteger(
@@ -698,7 +703,7 @@
         if (!mPendingScreenOff) {
             if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
                 animateScreenBrightness(brightness,
-                        slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
+                        slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : mBrightnessRampRateFast);
             } else {
                 animateScreenBrightness(brightness, 0);
             }
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 8813a61..1f6616e 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -335,7 +335,8 @@
 
     private ServiceInfo getServiceInfo(ComponentName name) {
         try {
-            return name != null ? mContext.getPackageManager().getServiceInfo(name, 0) : null;
+            return name != null ? mContext.getPackageManager().getServiceInfo(name,
+                    PackageManager.MATCH_DEBUG_TRIAGED_MISSING) : null;
         } catch (NameNotFoundException e) {
             return null;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index a36e671..69c012e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -165,15 +165,13 @@
     @ServiceThreadOnly
     protected void onStandby(boolean initiatedByCec, int standbyAction) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled() || initiatedByCec) {
+        if (!mService.isControlEnabled() || initiatedByCec || !mAutoTvOff) {
             return;
         }
         switch (standbyAction) {
             case HdmiControlService.STANDBY_SCREEN_OFF:
-                if (mAutoTvOff) {
-                    mService.sendCecCommand(
-                            HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
-                }
+                mService.sendCecCommand(
+                        HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
                 break;
             case HdmiControlService.STANDBY_SHUTDOWN:
                 // ACTION_SHUTDOWN is taken as a signal to power off all the devices.
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index 0b201710..537df81 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -21,6 +21,7 @@
 import android.os.SystemClock;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.Log;
 
 import java.util.HashMap;
 
@@ -42,6 +43,7 @@
     // Logging duration for same error message.
     private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000;  // 20s
 
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
     private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
@@ -83,10 +85,9 @@
     }
 
     private void debugInternal(String logMessage) {
-        if (true || IS_USER_BUILD) {
-            return;
+        if (DEBUG) {
+            Slog.d(TAG, logMessage);
         }
-        Slog.d(TAG, logMessage);
     }
 
     private static final String toLogString(String logMessage, Object[] objs) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c75e287..612bae2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -49,7 +49,9 @@
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -1729,7 +1731,7 @@
 
         if (wlUids.length > 0) {
             for (int uid : wlUids) {
-                removeRestrictBackgroundWhitelistedUidLocked(uid, false);
+                removeRestrictBackgroundWhitelistedUidLocked(uid, false, false);
             }
             writePolicy = true;
         }
@@ -1896,10 +1898,12 @@
         try {
             maybeRefreshTrustedTime();
             synchronized (mRulesLock) {
-                mRestrictBackground = restrictBackground;
-                updateRulesForRestrictBackgroundLocked();
-                updateNotificationsLocked();
-                writePolicyLocked();
+                if (restrictBackground == mRestrictBackground) {
+                    // Ideally, UI should never allow this scenario...
+                    Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
+                    return;
+                }
+                setRestrictBackgroundLocked(restrictBackground);
             }
 
         } finally {
@@ -1910,17 +1914,40 @@
                 .sendToTarget();
     }
 
+    private void setRestrictBackgroundLocked(boolean restrictBackground) {
+        final boolean oldRestrictBackground = mRestrictBackground;
+        mRestrictBackground = restrictBackground;
+        // Must whitelist foreground apps before turning data saver mode on.
+        // TODO: there is no need to iterate through all apps here, just those in the foreground,
+        // so it could call AM to get the UIDs of such apps, and iterate through them instead.
+        updateRulesForRestrictBackgroundLocked();
+        try {
+            if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
+                Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
+                mRestrictBackground = oldRestrictBackground;
+                // TODO: if it knew the foreground apps (see TODO above), it could call
+                // updateRulesForRestrictBackgroundLocked() again to restore state.
+                return;
+            }
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+        updateNotificationsLocked();
+        writePolicyLocked();
+    }
+
     @Override
     public void addRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        if (!isUidValidForRules(uid)) return;
-        final boolean changed;
+        final boolean oldStatus;
+        final boolean needFirewallRules;
         synchronized (mRulesLock) {
-            final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+            oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
             if (oldStatus) {
                 if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
                 return;
             }
+            needFirewallRules = isUidValidForWhitelistRules(uid);
             Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
             mRestrictBackgroundWhitelistUids.append(uid, true);
             if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
@@ -1929,13 +1956,14 @@
                         + " from revoked restrict background whitelist");
                 mRestrictBackgroundWhitelistRevokedUids.delete(uid);
             }
-            changed = mRestrictBackground && !oldStatus;
-            if (changed && hasInternetPermissions(uid)) {
-                setUidNetworkRules(uid, false);
+            if (needFirewallRules) {
+                // Only update firewall rules if necessary...
+                updateRuleForRestrictBackgroundLocked(uid);
             }
+            // ...but always persists the whitelist request.
             writePolicyLocked();
         }
-        if (changed) {
+        if (mRestrictBackground && !oldStatus && needFirewallRules) {
             mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
                     .sendToTarget();
         }
@@ -1944,10 +1972,9 @@
     @Override
     public void removeRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        if (!isUidValidForRules(uid)) return;
         final boolean changed;
         synchronized (mRulesLock) {
-            changed = removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+            changed = removeRestrictBackgroundWhitelistedUidLocked(uid, false, true);
         }
         if (changed) {
             mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
@@ -1955,14 +1982,19 @@
         }
     }
 
-    private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) {
+    /**
+     * Removes a uid from the restricted background whitelist, returning whether its current
+     * {@link ConnectivityManager.RestrictBackgroundStatus} changed.
+     */
+    private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean uidDeleted,
+            boolean updateNow) {
         final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
         if (!oldStatus) {
             if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
             return false;
         }
+        final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
         Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
-        final boolean changed = mRestrictBackground && oldStatus;
         mRestrictBackgroundWhitelistUids.delete(uid);
         if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
                 && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
@@ -1970,13 +2002,17 @@
                     + " to revoked restrict background whitelist");
             mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
         }
+        if (needFirewallRules) {
+            // Only update firewall rules if necessary...
+            updateRuleForRestrictBackgroundLocked(uid, uidDeleted);
+        }
         if (updateNow) {
-            if (changed && hasInternetPermissions(uid)) {
-                setUidNetworkRules(uid, true);
-            }
+            // ...but always persists the whitelist request.
             writePolicyLocked();
         }
-        return changed;
+        // Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
+        // app was whitelisted before).
+        return mRestrictBackground && needFirewallRules;
     }
 
     @Override
@@ -2268,7 +2304,12 @@
                 final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 fout.print(" state=");
                 fout.print(state);
-                fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)");
+                if (state <= ActivityManager.PROCESS_STATE_TOP) {
+                    fout.print(" (fg)");
+                } else {
+                    fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+                            ? " (fg svc)" : " (bg)");
+                }
 
                 final int rule = mUidRules.get(uid, RULE_UNKNOWN);
                 fout.print(" rule=");
@@ -2305,6 +2346,11 @@
                 mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
     }
 
+    private boolean isUidForegroundOnRestrictBackgroundLocked(int uid) {
+        final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        return isProcStateAllowedWhileOnRestrictBackgroundLocked(procState);
+    }
+
     private boolean isUidStateForegroundLocked(int state) {
         // only really in foreground when screen is also on
         return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
@@ -2312,7 +2358,7 @@
 
     /**
      * Process state of UID changed; if needed, will trigger
-     * {@link #updateRestrictDataRulesForUidLocked(int)}.
+     * {@link #updateRuleForRestrictBackgroundLocked(int)}.
      */
     private void updateUidStateLocked(int uid, int uidState) {
         final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
@@ -2363,8 +2409,10 @@
 
     private void updateRestrictBackgroundRulesOnUidStatusChangedLocked(int uid, int oldUidState,
             int newUidState) {
-        final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP;
-        final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP;
+        final boolean oldForeground =
+                isProcStateAllowedWhileOnRestrictBackgroundLocked(oldUidState);
+        final boolean newForeground =
+                isProcStateAllowedWhileOnRestrictBackgroundLocked(newUidState);
         if (oldForeground != newForeground) {
             updateRuleForRestrictBackgroundLocked(uid);
         }
@@ -2388,7 +2436,7 @@
         // only update rules for anyone with foreground activities
         final int size = mUidState.size();
         for (int i = 0; i < size; i++) {
-            if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_TOP) {
+            if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
                 final int uid = mUidState.keyAt(i);
                 updateRestrictionRulesForUidLocked(uid);
             }
@@ -2399,6 +2447,10 @@
         return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
     }
 
+    static boolean isProcStateAllowedWhileOnRestrictBackgroundLocked(int procState) {
+        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+    }
+
     void updateRulesForRestrictPowerLocked() {
         updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
                 mUidFirewallPowerSaveRules);
@@ -2492,7 +2544,7 @@
     }
 
     void updateRuleForAppIdleLocked(int uid) {
-        if (!isUidValidForRules(uid)) return;
+        if (!isUidValidForBlacklistRules(uid)) return;
 
         int appId = UserHandle.getAppId(uid);
         if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)) {
@@ -2519,6 +2571,7 @@
         updateRulesForAppIdleLocked();
         updateRulesForRestrictPowerLocked();
         updateRulesForRestrictBackgroundLocked();
+        setRestrictBackgroundLocked(mRestrictBackground);
 
         // If the set of restricted networks may have changed, re-evaluate those.
         if (restrictedNetworksChanged) {
@@ -2552,10 +2605,6 @@
                 updateRuleForRestrictBackgroundLocked(uid);
             }
         }
-
-        // limit data usage for some internal system services
-        updateRuleForRestrictBackgroundLocked(android.os.Process.MEDIA_UID);
-        updateRuleForRestrictBackgroundLocked(android.os.Process.DRM_UID);
     }
 
     private void updateRulesForTempWhitelistChangeLocked() {
@@ -2572,16 +2621,22 @@
         }
     }
 
-    private boolean isUidValidForRules(int uid) {
-        // allow rules on specific system services, and any apps (that have network access)
+    // TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both
+    // methods below could be merged into a isUidValidForRules() method.
+    private boolean isUidValidForBlacklistRules(int uid) {
+        // allow rules on specific system services, and any apps
         if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
-                || (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
+            || (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
             return true;
         }
 
         return false;
     }
 
+    private boolean isUidValidForWhitelistRules(int uid) {
+        return UserHandle.isApp(uid) && hasInternetPermissions(uid);
+    }
+
     private boolean isUidIdle(int uid) {
         final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
         final int userId = UserHandle.getUserId(uid);
@@ -2626,45 +2681,142 @@
         updateRuleForRestrictBackgroundLocked(uid);
     }
 
+    /**
+     * Applies network rules to bandwidth controllers based on process state and user-defined
+     * restrictions (blacklist / whitelist).
+     *
+     * <p>
+     * {@code netd} defines 3 firewall chains that govern whether an app has access to metered
+     * networks:
+     * <ul>
+     * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (blacklist).
+     * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're
+     *     also blacklisted.
+     * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}),
+     *     no UIDs other those whitelisted will have access.
+     * <ul>
+     *
+     * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the
+     * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundWhitelistedUid(int)} /
+     * {@link #removeRestrictBackgroundWhitelistedUid(int)} methods (for blacklist and whitelist
+     * respectively): these methods set the proper internal state (blacklist / whitelist), then call
+     * this ({@link #updateRuleForRestrictBackgroundLocked(int)}) to propagate the rules to
+     * {@link INetworkManagementService}, but this method should also be called in events (like
+     * Data Saver Mode flips or UID state changes) that might affect the foreground app, since the
+     * following rules should also be applied:
+     *
+     * <ul>
+     * <li>When Data Saver mode is on, the foreground app should be temporarily added to
+     *     {@code bw_happy_box} before the @{code bw_data_saver} chain is enabled.
+     * <li>If the foreground app is blacklisted by the user, it should be temporarily removed from
+     *     {@code bw_penalty_box}.
+     * <li>When the app leaves foreground state, the temporary changes above should be reverted.
+     * </ul>
+     *
+     * <p>For optimization, the rules are only applied on user apps that have internet access
+     * permission, since there is no need to change the {@code iptables} rule if the app does not
+     * have permission to use the internet.
+     *
+     * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
+     */
     private void updateRuleForRestrictBackgroundLocked(int uid) {
-        if (!isUidValidForRules(uid)) return;
+        updateRuleForRestrictBackgroundLocked(uid, false);
+    }
+
+    /**
+     * Overloaded version of {@link #updateRuleForRestrictBackgroundLocked(int)} called when an
+     * app is removed - it ignores the UID validity check.
+     */
+    private void updateRuleForRestrictBackgroundLocked(int uid, boolean uidDeleted) {
+        if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
+            if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
+            return;
+        }
 
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
-        final boolean uidForeground = isUidForegroundLocked(uid);
+        final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid);
+        final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
+        final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
 
-        // Derive active rules based on policy and active state
         int newRule = RULE_ALLOW_ALL;
+        final int oldRule = mUidRules.get(uid);
 
-        if (!uidForeground) {
-            // If the app is not in foreground, reject access if:
-            // - app is blacklisted by policy or
-            // - data saver mode is and app is not whitelisted
-            if (((uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0)
-                || (mRestrictBackground && !mRestrictBackgroundWhitelistUids.get(uid))) {
+        // First step: define the new rule based on user restrictions and foreground state.
+        if (isForeground) {
+            if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {
+                newRule = RULE_TEMPORARY_ALLOW_METERED;
+            }
+        } else {
+            if (isBlacklisted) {
                 newRule = RULE_REJECT_METERED;
+            } else if (isWhitelisted) {
+                newRule = RULE_ALLOW_METERED;
             }
         }
 
-        final int oldRule = mUidRules.get(uid);
         if (LOGV) {
-            Log.v(TAG, "updateRulesForRestrictBackgroundLocked(" + uid + "): oldRule = "
-                + ruleToString(oldRule) + ", newRule = " + ruleToString(newRule));
+            Log.v(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + "):"
+                    + " isForeground=" +isForeground + ", isBlacklisted: " + isBlacklisted
+                    + ", isWhitelisted: " + isWhitelisted + ", newRule: " + ruleToString(newRule)
+                    + ", oldRule: " + ruleToString(oldRule));
         }
 
+
         if (newRule == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
         } else {
             mUidRules.put(uid, newRule);
         }
 
-        if (oldRule != newRule) {
-            final boolean rejectMetered = (newRule == RULE_REJECT_METERED);
-            setUidNetworkRules(uid, rejectMetered);
+        // Second step: apply bw changes based on change of state.
+        if (newRule != oldRule) {
+            if (newRule == RULE_TEMPORARY_ALLOW_METERED) {
+                // Temporarily whitelist foreground app, removing from blacklist if necessary
+                // (since bw_penalty_box prevails over bw_happy_box).
+
+                setMeteredNetworkWhitelist(uid, true);
+                // TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
+                // but ideally it should be just:
+                //    setMeteredNetworkBlacklist(uid, isBlacklisted);
+                if (isBlacklisted) {
+                    setMeteredNetworkBlacklist(uid, false);
+                }
+            } else if (oldRule == RULE_TEMPORARY_ALLOW_METERED) {
+                // Remove temporary whitelist from app that is not on foreground anymore.
+
+                // TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
+                // but ideally they should be just:
+                //    setMeteredNetworkWhitelist(uid, isWhitelisted);
+                //    setMeteredNetworkBlacklist(uid, isBlacklisted);
+                if (!isWhitelisted) {
+                    setMeteredNetworkWhitelist(uid, false);
+                }
+                if (isBlacklisted) {
+                    setMeteredNetworkBlacklist(uid, true);
+                }
+            } else if (newRule == RULE_REJECT_METERED || oldRule == RULE_REJECT_METERED) {
+                // Flip state because app was explicitly added or removed to blacklist.
+                setMeteredNetworkBlacklist(uid, isBlacklisted);
+                if (oldRule == RULE_REJECT_METERED && isWhitelisted) {
+                    // Since blacklist prevails over whitelist, we need to handle the special case
+                    // where app is whitelisted and blacklisted at the same time (although such
+                    // scenario should be blocked by the UI), then blacklist is removed.
+                    setMeteredNetworkWhitelist(uid, isWhitelisted);
+                }
+            } else if (newRule == RULE_ALLOW_METERED || oldRule == RULE_ALLOW_METERED) {
+                // Flip state because app was explicitly added or removed to whitelist.
+                setMeteredNetworkWhitelist(uid, isWhitelisted);
+            } else {
+                // All scenarios should have been covered above
+                Log.wtf(TAG, "Unexpected change of state for " + uid
+                        + ": foreground=" + isForeground + ", whitelisted=" + isWhitelisted
+                        + ", blacklisted=" + isBlacklisted + ", newRule="
+                        + ruleToString(newRule) + ", oldRule=" + ruleToString(oldRule));
+            }
 
             // dispatch changed rule to existing listeners
             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newRule).sendToTarget();
         }
-
     }
 
     private class AppIdleStateChangeListener
@@ -2825,11 +2977,23 @@
         }
     }
 
-    private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+    private void setMeteredNetworkBlacklist(int uid, boolean enable) {
+        if (LOGV) Slog.v(TAG, "setMeteredNetworkBlacklist " + uid + ": " + enable);
         try {
-            mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces);
+            mNetworkManager.setUidMeteredNetworkBlacklist(uid, enable);
         } catch (IllegalStateException e) {
-            Log.wtf(TAG, "problem setting uid rules", e);
+            Log.wtf(TAG, "problem setting blacklist (" + enable + ") rules for " + uid, e);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
+    private void setMeteredNetworkWhitelist(int uid, boolean enable) {
+        if (LOGV) Slog.v(TAG, "setMeteredNetworkWhitelist " + uid + ": " + enable);
+        try {
+            mNetworkManager.setUidMeteredNetworkWhitelist(uid, enable);
+        } catch (IllegalStateException e) {
+            Log.wtf(TAG, "problem setting whitelist (" + enable + ") rules for " + uid, e);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
@@ -3011,7 +3175,7 @@
         public void onPackageRemoved(String packageName, int uid) {
             if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
             synchronized (mRulesLock) {
-                removeRestrictBackgroundWhitelistedUidLocked(uid, true);
+                removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
             }
         }
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 9cfb590..d339f69 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -24,7 +24,6 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -35,7 +34,6 @@
 import android.net.NetworkTemplate;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.util.Log;
@@ -88,12 +86,10 @@
         pw.println("    Adds a UID to the whitelist for restrict background usage.");
         pw.println("  add restrict-background-blacklist UID");
         pw.println("    Adds a UID to the blacklist for restrict background usage.");
-        pw.println("  get metered-network ID");
-        pw.println("    Checks whether the given non-mobile network is metered or not.");
         pw.println("  get restrict-background");
         pw.println("    Gets the global restrict background usage status.");
-        pw.println("  list metered-networks [BOOLEAN]");
-        pw.println("    Lists all non-mobile networks and whether they are metered or not.");
+        pw.println("  list wifi-networks [BOOLEAN]");
+        pw.println("    Lists all saved wifi networks and whether they are metered or not.");
         pw.println("    If a boolean argument is passed, filters just the metered (or unmetered)");
         pw.println("    networks.");
         pw.println("  list restrict-background-whitelist");
@@ -105,7 +101,7 @@
         pw.println("  remove restrict-background-blacklist UID");
         pw.println("    Removes a UID from the blacklist for restrict background usage.");
         pw.println("  set metered-network ID BOOLEAN");
-        pw.println("    Toggles whether the given non-mobile network is metered.");
+        pw.println("    Toggles whether the given wi-fi network is metered.");
         pw.println("  set restrict-background BOOLEAN");
         pw.println("    Sets the global restrict background usage status.");
     }
@@ -118,8 +114,6 @@
             return -1;
         }
         switch(type) {
-            case "metered-network":
-                return getMeteredWifiNetwork();
             case "restrict-background":
                 return getRestrictBackground();
         }
@@ -152,8 +146,8 @@
             return -1;
         }
         switch(type) {
-            case "metered-networks":
-                return listMeteredWifiNetworks();
+            case "wifi-networks":
+                return listWifiNetworks();
             case "restrict-background-whitelist":
                 return listRestrictBackgroundWhitelist();
             case "restrict-background-blacklist":
@@ -284,7 +278,7 @@
         return 0;
     }
 
-    private int listMeteredWifiNetworks() throws RemoteException {
+    private int listWifiNetworks() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String arg = getNextArg();
         final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
@@ -299,23 +293,6 @@
         return 0;
     }
 
-    private int getMeteredWifiNetwork() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        final String id = getNextArg();
-        if (id == null) {
-            pw.println("Error: didn't specify ID");
-            return -1;
-        }
-        final List<NetworkPolicy> policies = getWifiPolicies();
-        for (NetworkPolicy policy: policies) {
-            if (id.equals(getNetworkId(policy))) {
-                pw.println(policy.metered);
-                return 0;
-            }
-        }
-        return 0;
-    }
-
     private int setMeteredWifiNetwork() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String id = getNextArg();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0f23fde..124d7f1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -120,6 +120,7 @@
 import android.widget.Toast;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
@@ -226,7 +227,7 @@
     private VrManagerInternal mVrManagerInternal;
 
     final IBinder mForegroundToken = new Binder();
-    private WorkerHandler mHandler;
+    private Handler mHandler;
     private final HandlerThread mRankingThread = new HandlerThread("ranker",
             Process.THREAD_PRIORITY_BACKGROUND);
 
@@ -572,33 +573,9 @@
         public void clearEffects() {
             synchronized (mNotificationList) {
                 if (DBG) Slog.d(TAG, "clearEffects");
-
-                // sound
-                mSoundNotificationKey = null;
-
-                long identity = Binder.clearCallingIdentity();
-                try {
-                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
-                    if (player != null) {
-                        player.stopAsync();
-                    }
-                } catch (RemoteException e) {
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-
-                // vibrate
-                mVibrateNotificationKey = null;
-                identity = Binder.clearCallingIdentity();
-                try {
-                    mVibrator.cancel();
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-
-                // light
-                mLights.clear();
-                updateLightsLocked();
+                clearSoundLocked();
+                clearVibrateLocked();
+                clearLightsLocked();
             }
         }
 
@@ -658,6 +635,36 @@
         }
     };
 
+    private void clearSoundLocked() {
+        mSoundNotificationKey = null;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+            if (player != null) {
+                player.stopAsync();
+            }
+        } catch (RemoteException e) {
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void clearVibrateLocked() {
+        mVibrateNotificationKey = null;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mVibrator.cancel();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void clearLightsLocked() {
+        // light
+        mLights.clear();
+        updateLightsLocked();
+    }
+
     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -863,6 +870,26 @@
         super(context);
     }
 
+    @VisibleForTesting
+    void setAudioManager(AudioManager audioMananger) {
+        mAudioManager = audioMananger;
+    }
+
+    @VisibleForTesting
+    void setVibrator(Vibrator vibrator) {
+        mVibrator = vibrator;
+    }
+
+    @VisibleForTesting
+    void setSystemReady(boolean systemReady) {
+        mSystemReady = systemReady;
+    }
+
+    @VisibleForTesting
+    void setHandler(Handler handler) {
+        mHandler = handler;
+    }
+
     @Override
     public void onStart() {
         Resources resources = getContext().getResources();
@@ -1852,10 +1879,16 @@
         }
 
         private boolean checkPolicyAccess(String pkg) {
-            if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
-                    android.Manifest.permission.MANAGE_NOTIFICATIONS, Binder.getCallingUid(),
-                    -1, true)) {
-                return true;
+            try {
+                int uid = getContext().getPackageManager().getPackageUidAsUser(
+                        pkg, UserHandle.getCallingUserId());
+                if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
+                        -1, true)) {
+                    return true;
+                }
+            } catch (NameNotFoundException e) {
+                return false;
             }
             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
         }
@@ -2486,12 +2519,14 @@
         return false;
     }
 
-    private void buzzBeepBlinkLocked(NotificationRecord record) {
+    @VisibleForTesting
+    void buzzBeepBlinkLocked(NotificationRecord record) {
         boolean buzz = false;
         boolean beep = false;
         boolean blink = false;
 
         final Notification notification = record.sbn.getNotification();
+        final String key = record.getKey();
 
         // Should this notification make noise, vibe, or use the LED?
         final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
@@ -2515,9 +2550,15 @@
         if (disableEffects != null) {
             ZenLog.traceDisableEffects(record, disableEffects);
         }
+
+        // Remember if this notification already owns the notification channels.
+        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
+        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
+
+        // These are set inside the conditional if the notification is allowed to make noise.
+        boolean hasValidVibrate = false;
+        boolean hasValidSound = false;
         if (disableEffects == null
-                && (!(record.isUpdate
-                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                 && (record.getUserId() == UserHandle.USER_ALL ||
                     record.getUserId() == currentUser ||
                     mUserProfiles.isCurrentProfile(record.getUserId()))
@@ -2526,10 +2567,6 @@
                 && mAudioManager != null) {
             if (DBG) Slog.v(TAG, "Interrupting!");
 
-            sendAccessibilityEvent(notification, record.sbn.getPackageName());
-
-            // sound
-
             // should we use the default notification sound? (indicated either by
             // DEFAULT_SOUND or because notification.sound is pointing at
             // Settings.System.NOTIFICATION_SOUND)
@@ -2539,8 +2576,6 @@
                                    .equals(notification.sound);
 
             Uri soundUri = null;
-            boolean hasValidSound = false;
-
             if (useDefaultSound) {
                 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
 
@@ -2553,88 +2588,105 @@
                 hasValidSound = (soundUri != null);
             }
 
-            if (hasValidSound) {
-                boolean looping =
-                        (notification.flags & Notification.FLAG_INSISTENT) != 0;
-                AudioAttributes audioAttributes = audioAttributesForNotification(notification);
-                mSoundNotificationKey = record.getKey();
-                // do not play notifications if stream volume is 0 (typically because
-                // ringer mode is silent) or if there is a user of exclusive audio focus
-                if ((mAudioManager.getStreamVolume(
-                        AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
-                            && !mAudioManager.isAudioFocusExclusive()) {
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        final IRingtonePlayer player =
-                                mAudioManager.getRingtonePlayer();
-                        if (player != null) {
-                            if (DBG) Slog.v(TAG, "Playing sound " + soundUri
-                                    + " with attributes " + audioAttributes);
-                            player.playAsync(soundUri, record.sbn.getUser(), looping,
-                                    audioAttributes);
-                            beep = true;
-                        }
-                    } catch (RemoteException e) {
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                }
-            }
-
-            // vibrate
             // Does the notification want to specify its own vibration?
             final boolean hasCustomVibrate = notification.vibrate != null;
 
             // new in 4.2: if there was supposed to be a sound and we're in vibrate
             // mode, and no other vibration is specified, we fall back to vibration
             final boolean convertSoundToVibration =
-                       !hasCustomVibrate
-                    && hasValidSound
-                    && (mAudioManager.getRingerModeInternal()
-                               == AudioManager.RINGER_MODE_VIBRATE);
+                    !hasCustomVibrate
+                            && hasValidSound
+                            && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
 
             // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
             final boolean useDefaultVibrate =
                     (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
 
-            if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
-                    && !(mAudioManager.getRingerModeInternal()
-                            == AudioManager.RINGER_MODE_SILENT)) {
-                mVibrateNotificationKey = record.getKey();
+            hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
+                    hasCustomVibrate;
 
-                if (useDefaultVibrate || convertSoundToVibration) {
-                    // Escalate privileges so we can use the vibrator even if the
-                    // notifying app does not have the VIBRATE permission.
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
-                            useDefaultVibrate ? mDefaultVibrationPattern
-                                : mFallbackVibrationPattern,
-                            ((notification.flags & Notification.FLAG_INSISTENT) != 0)
-                                ? 0: -1, audioAttributesForNotification(notification));
-                        buzz = true;
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
+            // We can alert, and we're allowed to alert, but if the developer asked us to only do
+            // it once, and we already have, then don't.
+            if (!(record.isUpdate
+                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
+
+                sendAccessibilityEvent(notification, record.sbn.getPackageName());
+
+                if (hasValidSound) {
+                    boolean looping =
+                            (notification.flags & Notification.FLAG_INSISTENT) != 0;
+                    AudioAttributes audioAttributes = audioAttributesForNotification(notification);
+                    mSoundNotificationKey = key;
+                    // do not play notifications if stream volume is 0 (typically because
+                    // ringer mode is silent) or if there is a user of exclusive audio focus
+                    if ((mAudioManager.getStreamVolume(
+                            AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
+                            && !mAudioManager.isAudioFocusExclusive()) {
+                        final long identity = Binder.clearCallingIdentity();
+                        try {
+                            final IRingtonePlayer player =
+                                    mAudioManager.getRingtonePlayer();
+                            if (player != null) {
+                                if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+                                        + " with attributes " + audioAttributes);
+                                player.playAsync(soundUri, record.sbn.getUser(), looping,
+                                        audioAttributes);
+                                beep = true;
+                            }
+                        } catch (RemoteException e) {
+                        } finally {
+                            Binder.restoreCallingIdentity(identity);
+                        }
                     }
-                } else if (notification.vibrate.length > 1) {
-                    // If you want your own vibration pattern, you need the VIBRATE
-                    // permission
-                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
-                            notification.vibrate,
-                        ((notification.flags & Notification.FLAG_INSISTENT) != 0)
-                                ? 0: -1, audioAttributesForNotification(notification));
-                    buzz = true;
+                }
+
+                if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
+                        == AudioManager.RINGER_MODE_SILENT)) {
+                    mVibrateNotificationKey = key;
+
+                    if (useDefaultVibrate || convertSoundToVibration) {
+                        // Escalate privileges so we can use the vibrator even if the
+                        // notifying app does not have the VIBRATE permission.
+                        long identity = Binder.clearCallingIdentity();
+                        try {
+                            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                                    useDefaultVibrate ? mDefaultVibrationPattern
+                                            : mFallbackVibrationPattern,
+                                    ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+                                            ? 0: -1, audioAttributesForNotification(notification));
+                            buzz = true;
+                        } finally {
+                            Binder.restoreCallingIdentity(identity);
+                        }
+                    } else if (notification.vibrate.length > 1) {
+                        // If you want your own vibration pattern, you need the VIBRATE
+                        // permission
+                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                                notification.vibrate,
+                                ((notification.flags & Notification.FLAG_INSISTENT) != 0)
+                                        ? 0: -1, audioAttributesForNotification(notification));
+                        buzz = true;
+                    }
                 }
             }
+
+        }
+        // If a notification is updated to remove the actively playing sound or vibrate,
+        // cancel that feedback now
+        if (wasBeep && !hasValidSound) {
+            clearSoundLocked();
+        }
+        if (wasBuzz && !hasValidVibrate) {
+            clearVibrateLocked();
         }
 
         // light
         // release the light
-        boolean wasShowLights = mLights.remove(record.getKey());
+        boolean wasShowLights = mLights.remove(key);
         if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
                 && ((record.getSuppressedVisualEffects()
                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
-            mLights.add(record.getKey());
+            mLights.add(key);
             updateLightsLocked();
             if (mUseAttentionLight) {
                 mAttentionLight.pulse();
@@ -2648,7 +2700,7 @@
                     & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
                 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
             } else {
-                EventLogTags.writeNotificationAlert(record.getKey(),
+                EventLogTags.writeNotificationAlert(key,
                         buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
                 mHandler.post(mBuzzBeepBlinked);
             }
@@ -3435,6 +3487,9 @@
             return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
         } catch (RemoteException re) {
             throw new SecurityException("Could not talk to package manager service");
+        } catch (IllegalArgumentException ex) {
+            // Package not found.
+            return false;
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 13a96ae..098b39e 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -247,10 +247,8 @@
             }
 
             // SetupWizard
-            Intent setupIntent = new Intent(Intent.ACTION_MAIN);
-            setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
-            PackageParser.Package setupPackage = getDefaultSystemHandlerActivityPackageLPr(
-                    setupIntent, userId);
+            PackageParser.Package setupPackage = getSystemPackageLPr(
+                    mService.mSetupWizardPackage);
             if (setupPackage != null
                     && doesPackageSupportRuntimePermissions(setupPackage)) {
                 grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
@@ -597,6 +595,16 @@
                 grantRuntimePermissionsLPw(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
             }
 
+            // NFC Tag viewer
+            Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
+            nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
+            PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackageLPr(
+                    nfcTagIntent, userId);
+            if (nfcTagPkg != null
+                    && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
+                grantRuntimePermissionsLPw(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
+                grantRuntimePermissionsLPw(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
+            }
             mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
         }
     }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7c71fbc..4899e34 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -60,6 +60,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -121,6 +122,21 @@
             return getCallingUid();
         }
 
+        final int injectCallingUserId() {
+            return UserHandle.getUserId(injectBinderCallingUid());
+        }
+
+        @VisibleForTesting
+        long injectClearCallingIdentity() {
+            return Binder.clearCallingIdentity();
+        }
+
+        // Injection point.
+        @VisibleForTesting
+        void injectRestoreCallingIdentity(long token) {
+            Binder.restoreCallingIdentity(token);
+        }
+
         private int getCallingUserId() {
             return UserHandle.getUserId(injectBinderCallingUid());
         }
@@ -197,14 +213,13 @@
         /**
          * Checks if the caller is in the same group as the userToCheck.
          */
-        @VisibleForTesting // We override it in unit tests
-        void ensureInUserProfiles(UserHandle userToCheck, String message) {
-            final int callingUserId = UserHandle.getCallingUserId();
+        private void ensureInUserProfiles(UserHandle userToCheck, String message) {
+            final int callingUserId = injectCallingUserId();
             final int targetUserId = userToCheck.getIdentifier();
 
             if (targetUserId == callingUserId) return;
 
-            long ident = Binder.clearCallingIdentity();
+            long ident = injectClearCallingIdentity();
             try {
                 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
                 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
@@ -214,7 +229,7 @@
                     throw new SecurityException(message);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                injectRestoreCallingIdentity(ident);
             }
         }
 
@@ -239,12 +254,12 @@
          * Checks if the user is enabled.
          */
         private boolean isUserEnabled(UserHandle user) {
-            long ident = Binder.clearCallingIdentity();
+            long ident = injectClearCallingIdentity();
             try {
                 UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
                 return targetUserInfo != null && targetUserInfo.isEnabled();
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                injectRestoreCallingIdentity(ident);
             }
         }
 
@@ -345,6 +360,9 @@
         public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
                 String packageName, ComponentName componentName, int flags, UserHandle user) {
             ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return new ParceledListSlice<>(new ArrayList(0));
+            }
 
             return new ParceledListSlice<>(
                     mShortcutServiceInternal.getShortcuts(getCallingUserId(),
@@ -356,6 +374,9 @@
         public ParceledListSlice getShortcutInfo(String callingPackage, String packageName,
                 List<String> ids, UserHandle user) {
             ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return new ParceledListSlice<>(new ArrayList(0));
+            }
 
             return new ParceledListSlice<>(
                     mShortcutServiceInternal.getShortcutInfo(getCallingUserId(),
@@ -366,6 +387,10 @@
         public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
                 UserHandle user) {
             ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                throw new IllegalStateException("Cannot pin shortcuts for disabled profile "
+                        + user);
+            }
 
             mShortcutServiceInternal.pinShortcuts(getCallingUserId(),
                     callingPackage, packageName, ids, user.getIdentifier());
@@ -375,6 +400,9 @@
         public int getShortcutIconResId(String callingPackage, ShortcutInfo shortcut,
                 UserHandle user) {
             ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return 0;
+            }
 
             return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
                     callingPackage, shortcut, user.getIdentifier());
@@ -384,6 +412,9 @@
         public ParcelFileDescriptor getShortcutIconFd(String callingPackage, ShortcutInfo shortcut,
                 UserHandle user) {
             ensureShortcutPermission(callingPackage, user);
+            if (!isUserEnabled(user)) {
+                return null;
+            }
 
             return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
                     callingPackage, shortcut, user.getIdentifier());
@@ -402,6 +433,11 @@
             verifyCallingPackage(callingPackage);
             ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
 
+            if (!isUserEnabled(user)) {
+                throw new IllegalStateException("Cannot start a shortcut for disabled profile "
+                        + user);
+            }
+
             // Even without the permission, pinned shortcuts are always launchable.
             if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
                     callingPackage, packageName, shortcutId, user.getIdentifier())) {
@@ -530,13 +566,13 @@
 
         /** Checks if user is a profile of or same as listeningUser.
          * and the user is enabled. */
-        boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+        private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
                 String debugMsg) {
             if (user.getIdentifier() == listeningUser.getIdentifier()) {
                 if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
                 return true;
             }
-            long ident = Binder.clearCallingIdentity();
+            long ident = injectClearCallingIdentity();
             try {
                 UserInfo userInfo = mUm.getUserInfo(user.getIdentifier());
                 UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
@@ -557,7 +593,7 @@
                     return true;
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                injectRestoreCallingIdentity(ident);
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4ca615d..d13f472 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -42,7 +42,7 @@
 import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
 
 /**
  * Helper class for running dexopt command on packages.
@@ -144,9 +144,10 @@
                 if (isUsedByOtherApps(path)) {
                     checkProfiles = false;
 
-                    // TODO: Should we only upgrade to the non-profile-guided version? That is,
-                    //       given verify-profile, should we move to interpret-only?
-                    targetCompilerFilter = getFullCompilerFilter();
+                    targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+                    if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
+                        throw new IllegalStateException(targetCompilerFilter);
+                    }
                     isProfileGuidedFilter = false;
 
                     break;
@@ -181,6 +182,10 @@
                     return DEX_OPT_FAILED;
                 }
                 dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
+                if (PackageManagerService.DEBUG_DEXOPT) {
+                    Log.i(TAG, "DexoptNeeded for " + path + "@" + targetCompilerFilter + " is " +
+                            dexoptNeeded);
+                }
 
                 final String dexoptType;
                 String oatDir = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 926ff37..4ce730f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -64,6 +64,7 @@
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
 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_DEVICE_ADMIN;
@@ -75,6 +76,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
 import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
@@ -114,6 +116,7 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentFilter.AuthorityEntry;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
@@ -146,6 +149,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.IntentInfo;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageStats;
@@ -319,6 +323,7 @@
     private static final boolean DEBUG_INTENT_MATCHING = false;
     private static final boolean DEBUG_PACKAGE_SCANNING = false;
     private static final boolean DEBUG_VERIFY = false;
+    private static final boolean DEBUG_FILTERS = false;
 
     // Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
     // and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -444,6 +449,18 @@
         sBrowserIntent.setData(Uri.parse("http:"));
     }
 
+    /**
+     * The set of all protected actions [i.e. those actions for which a high priority
+     * intent filter is disallowed].
+     */
+    private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
+    static {
+        PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
+        PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
+        PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
+        PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
+    }
+
     // Compilation reasons.
     public static final int REASON_FIRST_BOOT = 0;
     public static final int REASON_BOOT = 1;
@@ -530,6 +547,20 @@
      * are package location.
      */
     final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+    /**
+     * Tracks high priority intent filters for protected actions. During boot, certain
+     * filter actions are protected and should never be allowed to have a high priority
+     * intent filter for them. However, there is one, and only one exception -- the
+     * setup wizard. It must be able to define a high priority intent filter for these
+     * actions to ensure there are no escapes from the wizard. We need to delay processing
+     * of these during boot as we need to look at all of the system packages in order
+     * to know which component is the setup wizard.
+     */
+    private final List<PackageParser.ActivityIntentInfo> mProtectedFilters = new ArrayList<>();
+    /**
+     * Whether or not processing protected filters should be deferred.
+     */
+    private boolean mDeferProtectedFilters = true;
 
     /**
      * Tracks existing system packages prior to receiving an OTA. Keys are package name.
@@ -1034,6 +1065,7 @@
 
     final @Nullable String mRequiredVerifierPackage;
     final @Nullable String mRequiredInstallerPackage;
+    final @Nullable String mSetupWizardPackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
 
@@ -2427,6 +2459,36 @@
             }
             mExpectingBetter.clear();
 
+            // Resolve protected action filters. Only the setup wizard is allowed to
+            // have a high priority filter for these actions.
+            mSetupWizardPackage = getSetupWizardPackageName();
+            if (mProtectedFilters.size() > 0) {
+                if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+                    Slog.i(TAG, "No setup wizard;"
+                        + " All protected intents capped to priority 0");
+                }
+                for (ActivityIntentInfo filter : mProtectedFilters) {
+                    if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
+                        if (DEBUG_FILTERS) {
+                            Slog.i(TAG, "Found setup wizard;"
+                                + " allow priority " + filter.getPriority() + ";"
+                                + " package: " + filter.activity.info.packageName
+                                + " activity: " + filter.activity.className
+                                + " priority: " + filter.getPriority());
+                        }
+                        // skip setup wizard; allow it to keep the high priority filter
+                        continue;
+                    }
+                    Slog.w(TAG, "Protected action; cap priority to 0;"
+                            + " package: " + filter.activity.info.packageName
+                            + " activity: " + filter.activity.className
+                            + " origPrio: " + filter.getPriority());
+                    filter.setPriority(0);
+                }
+            }
+            mDeferProtectedFilters = false;
+            mProtectedFilters.clear();
+
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
             updateAllSharedLibrariesLPw();
@@ -2886,12 +2948,15 @@
         return cur;
     }
 
-    PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
+    private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        final PackageSetting ps = (PackageSetting) p.mExtras;
         if (ps == null) {
             return null;
         }
+        final PackageParser.Package p = ps.pkg;
+        if (p == null) {
+            return null;
+        }
 
         final PermissionsState permissionsState = ps.getPermissionsState();
 
@@ -2961,14 +3026,28 @@
                 false /* requireFullPermission */, false /* checkShell */, "get package info");
         // reader
         synchronized (mPackages) {
-            PackageParser.Package p = mPackages.get(packageName);
+            final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
+            PackageParser.Package p = null;
+            if (matchFactoryOnly) {
+                final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+                if (ps != null) {
+                    return generatePackageInfo(ps, flags, userId);
+                }
+            }
+            if (p == null) {
+                p = mPackages.get(packageName);
+                if (matchFactoryOnly && !isSystemApp(p)) {
+                    return null;
+                }
+            }
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
-                return generatePackageInfo(p, flags, userId);
+                return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
             }
-            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
-                return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
+            if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                return generatePackageInfo(ps, flags, userId);
             }
         }
         return null;
@@ -3129,8 +3208,7 @@
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
-                PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName,
-                        flags, userId);
+                final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
                 if (pInfo != null) {
                     return pInfo.applicationInfo;
                 }
@@ -3142,31 +3220,6 @@
         return null;
     }
 
-    private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
-            int userId) {
-        if (!sUserManager.exists(userId)) return null;
-        PackageSetting ps = mSettings.mPackages.get(packageName);
-        if (ps != null) {
-            PackageParser.Package pkg = ps.pkg;
-            if (pkg == null) {
-                if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
-                    return null;
-                }
-                // Only data remains, so we aren't worried about code paths
-                pkg = new PackageParser.Package(packageName);
-                pkg.applicationInfo.packageName = packageName;
-                pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
-                pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
-                pkg.applicationInfo.uid = ps.appId;
-                pkg.applicationInfo.initForUser(userId);
-                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
-            }
-            return generatePackageInfo(pkg, flags, userId);
-        }
-        return null;
-    }
-
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
@@ -4944,8 +4997,10 @@
                             if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
                             continue;
                         }
-                        final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
-                                flags | MATCH_DISABLED_COMPONENTS, userId);
+                        final ActivityInfo ai = getActivityInfo(
+                                pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+                                        | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                                userId);
                         if (DEBUG_PREFERRED || debug) {
                             Slog.v(TAG, "Found preferred activity:");
                             if (ai != null) {
@@ -5913,11 +5968,11 @@
             if (listUninstalled) {
                 list = new ArrayList<PackageInfo>(mSettings.mPackages.size());
                 for (PackageSetting ps : mSettings.mPackages.values()) {
-                    PackageInfo pi;
+                    final PackageInfo pi;
                     if (ps.pkg != null) {
-                        pi = generatePackageInfo(ps.pkg, flags, userId);
+                        pi = generatePackageInfo(ps, flags, userId);
                     } else {
-                        pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+                        pi = generatePackageInfo(ps, flags, userId);
                     }
                     if (pi != null) {
                         list.add(pi);
@@ -5926,7 +5981,8 @@
             } else {
                 list = new ArrayList<PackageInfo>(mPackages.size());
                 for (PackageParser.Package p : mPackages.values()) {
-                    PackageInfo pi = generatePackageInfo(p, flags, userId);
+                    final PackageInfo pi =
+                            generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
                     if (pi != null) {
                         list.add(pi);
                     }
@@ -5953,11 +6009,11 @@
         if (numMatch == 0) {
             return;
         }
-        PackageInfo pi;
+        final PackageInfo pi;
         if (ps.pkg != null) {
-            pi = generatePackageInfo(ps.pkg, flags, userId);
+            pi = generatePackageInfo(ps, flags, userId);
         } else {
-            pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
+            pi = generatePackageInfo(ps, flags, userId);
         }
         // The above might return null in cases of uninstalled apps or install-state
         // skew across users/profiles.
@@ -9702,6 +9758,12 @@
                 // is granted only if it was already granted.
                 allowed = origPermissions.hasInstallPermission(perm);
             }
+            if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
+                    && pkg.packageName.equals(mSetupWizardPackage)) {
+                // If this permission is to be granted to the system setup wizard and
+                // this app is a setup wizard, then it gets the permission.
+                allowed = true;
+            }
         }
         return allowed;
     }
@@ -9759,8 +9821,314 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
+        /**
+         * Finds a privileged activity that matches the specified activity names.
+         */
+        private PackageParser.Activity findMatchingActivity(
+                List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
+            for (PackageParser.Activity sysActivity : activityList) {
+                if (sysActivity.info.name.equals(activityInfo.name)) {
+                    return sysActivity;
+                }
+                if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+                    return sysActivity;
+                }
+                if (sysActivity.info.targetActivity != null) {
+                    if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+                        return sysActivity;
+                    }
+                    if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+                        return sysActivity;
+                    }
+                }
+            }
+            return null;
+        }
+
+        public class IterGenerator<E> {
+            public Iterator<E> generate(ActivityIntentInfo info) {
+                return null;
+            }
+        }
+
+        public class ActionIterGenerator extends IterGenerator<String> {
+            @Override
+            public Iterator<String> generate(ActivityIntentInfo info) {
+                return info.actionsIterator();
+            }
+        }
+
+        public class CategoriesIterGenerator extends IterGenerator<String> {
+            @Override
+            public Iterator<String> generate(ActivityIntentInfo info) {
+                return info.categoriesIterator();
+            }
+        }
+
+        public class SchemesIterGenerator extends IterGenerator<String> {
+            @Override
+            public Iterator<String> generate(ActivityIntentInfo info) {
+                return info.schemesIterator();
+            }
+        }
+
+        public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
+            @Override
+            public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+                return info.authoritiesIterator();
+            }
+        }
+
+        /**
+         * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
+         * MODIFIED. Do not pass in a list that should not be changed.
+         */
+        private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
+                IterGenerator<T> generator, Iterator<T> searchIterator) {
+            // loop through the set of actions; every one must be found in the intent filter
+            while (searchIterator.hasNext()) {
+                // we must have at least one filter in the list to consider a match
+                if (intentList.size() == 0) {
+                    break;
+                }
+
+                final T searchAction = searchIterator.next();
+
+                // loop through the set of intent filters
+                final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+                while (intentIter.hasNext()) {
+                    final ActivityIntentInfo intentInfo = intentIter.next();
+                    boolean selectionFound = false;
+
+                    // loop through the intent filter's selection criteria; at least one
+                    // of them must match the searched criteria
+                    final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+                    while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
+                        final T intentSelection = intentSelectionIter.next();
+                        if (intentSelection != null && intentSelection.equals(searchAction)) {
+                            selectionFound = true;
+                            break;
+                        }
+                    }
+
+                    // the selection criteria wasn't found in this filter's set; this filter
+                    // is not a potential match
+                    if (!selectionFound) {
+                        intentIter.remove();
+                    }
+                }
+            }
+        }
+
+        private boolean isProtectedAction(ActivityIntentInfo filter) {
+            final Iterator<String> actionsIter = filter.actionsIterator();
+            while (actionsIter != null && actionsIter.hasNext()) {
+                final String filterAction = actionsIter.next();
+                if (PROTECTED_ACTIONS.contains(filterAction)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Adjusts the priority of the given intent filter according to policy.
+         * <p>
+         * <ul>
+         * <li>The priority for non privileged applications is capped to '0'</li>
+         * <li>The priority for protected actions on privileged applications is capped to '0'</li>
+         * <li>The priority for unbundled updates to privileged applications is capped to the
+         *      priority defined on the system partition</li>
+         * </ul>
+         * <p>
+         * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
+         * allowed to obtain any priority on any action.
+         */
+        private void adjustPriority(
+                List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) {
+            // nothing to do; priority is fine as-is
+            if (intent.getPriority() <= 0) {
+                return;
+            }
+
+            final ActivityInfo activityInfo = intent.activity.info;
+            final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+
+            final boolean privilegedApp =
+                    ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+            if (!privilegedApp) {
+                // non-privileged applications can never define a priority >0
+                Slog.w(TAG, "Non-privileged app; cap priority to 0;"
+                        + " package: " + applicationInfo.packageName
+                        + " activity: " + intent.activity.className
+                        + " origPrio: " + intent.getPriority());
+                intent.setPriority(0);
+                return;
+            }
+
+            if (systemActivities == null) {
+                // the system package is not disabled; we're parsing the system partition
+                if (isProtectedAction(intent)) {
+                    if (mDeferProtectedFilters) {
+                        // We can't deal with these just yet. No component should ever obtain a
+                        // >0 priority for a protected actions, with ONE exception -- the setup
+                        // wizard. The setup wizard, however, cannot be known until we're able to
+                        // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
+                        // until all intent filters have been processed. Chicken, meet egg.
+                        // Let the filter temporarily have a high priority and rectify the
+                        // priorities after all system packages have been scanned.
+                        mProtectedFilters.add(intent);
+                        if (DEBUG_FILTERS) {
+                            Slog.i(TAG, "Protected action; save for later;"
+                                    + " package: " + applicationInfo.packageName
+                                    + " activity: " + intent.activity.className
+                                    + " origPrio: " + intent.getPriority());
+                        }
+                        return;
+                    } else {
+                        if (DEBUG_FILTERS && mSetupWizardPackage == null) {
+                            Slog.i(TAG, "No setup wizard;"
+                                + " All protected intents capped to priority 0");
+                        }
+                        if (intent.activity.info.packageName.equals(mSetupWizardPackage)) {
+                            if (DEBUG_FILTERS) {
+                                Slog.i(TAG, "Found setup wizard;"
+                                    + " allow priority " + intent.getPriority() + ";"
+                                    + " package: " + intent.activity.info.packageName
+                                    + " activity: " + intent.activity.className
+                                    + " priority: " + intent.getPriority());
+                            }
+                            // setup wizard gets whatever it wants
+                            return;
+                        }
+                        Slog.w(TAG, "Protected action; cap priority to 0;"
+                                + " package: " + intent.activity.info.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                        intent.setPriority(0);
+                        return;
+                    }
+                }
+                // privileged apps on the system image get whatever priority they request
+                return;
+            }
+
+            // privileged app unbundled update ... try to find the same activity
+            final PackageParser.Activity foundActivity =
+                    findMatchingActivity(systemActivities, activityInfo);
+            if (foundActivity == null) {
+                // this is a new activity; it cannot obtain >0 priority
+                if (DEBUG_FILTERS) {
+                    Slog.i(TAG, "New activity; cap priority to 0;"
+                            + " package: " + applicationInfo.packageName
+                            + " activity: " + intent.activity.className
+                            + " origPrio: " + intent.getPriority());
+                }
+                intent.setPriority(0);
+                return;
+            }
+
+            // found activity, now check for filter equivalence
+
+            // a shallow copy is enough; we modify the list, not its contents
+            final List<ActivityIntentInfo> intentListCopy =
+                    new ArrayList<>(foundActivity.intents);
+            final List<ActivityIntentInfo> foundFilters = findFilters(intent);
+
+            // find matching action subsets
+            final Iterator<String> actionsIterator = intent.actionsIterator();
+            if (actionsIterator != null) {
+                getIntentListSubset(
+                        intentListCopy, new ActionIterGenerator(), actionsIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched action; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // find matching category subsets
+            final Iterator<String> categoriesIterator = intent.categoriesIterator();
+            if (categoriesIterator != null) {
+                getIntentListSubset(intentListCopy, new CategoriesIterGenerator(),
+                        categoriesIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched category; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // find matching schemes subsets
+            final Iterator<String> schemesIterator = intent.schemesIterator();
+            if (schemesIterator != null) {
+                getIntentListSubset(intentListCopy, new SchemesIterGenerator(),
+                        schemesIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // find matching authorities subsets
+            final Iterator<IntentFilter.AuthorityEntry>
+                    authoritiesIterator = intent.authoritiesIterator();
+            if (authoritiesIterator != null) {
+                getIntentListSubset(intentListCopy,
+                        new AuthoritiesIterGenerator(),
+                        authoritiesIterator);
+                if (intentListCopy.size() == 0) {
+                    // no more intents to match; we're not equivalent
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Mismatched authority; cap priority to 0;"
+                                + " package: " + applicationInfo.packageName
+                                + " activity: " + intent.activity.className
+                                + " origPrio: " + intent.getPriority());
+                    }
+                    intent.setPriority(0);
+                    return;
+                }
+            }
+
+            // we found matching filter(s); app gets the max priority of all intents
+            int cappedPriority = 0;
+            for (int i = intentListCopy.size() - 1; i >= 0; --i) {
+                cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority());
+            }
+            if (intent.getPriority() > cappedPriority) {
+                if (DEBUG_FILTERS) {
+                    Slog.i(TAG, "Found matching filter(s);"
+                            + " cap priority to " + cappedPriority + ";"
+                            + " package: " + applicationInfo.packageName
+                            + " activity: " + intent.activity.className
+                            + " origPrio: " + intent.getPriority());
+                }
+                intent.setPriority(cappedPriority);
+                return;
+            }
+            // all this for nothing; the requested priority was <= what was on the system
+        }
+
         public final void addActivity(PackageParser.Activity a, String type) {
-            final boolean systemApp = a.info.applicationInfo.isSystemApp();
             mActivities.put(a.getComponentName(), a);
             if (DEBUG_SHOW_INFO)
                 Log.v(
@@ -9771,10 +10139,12 @@
             final int NI = a.intents.size();
             for (int j=0; j<NI; j++) {
                 PackageParser.ActivityIntentInfo intent = a.intents.get(j);
-                if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
-                    intent.setPriority(0);
-                    Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
-                            + a.className + " with priority > 0, forcing to 0");
+                if ("activity".equals(type)) {
+                    final PackageSetting ps =
+                            mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
+                    final List<PackageParser.Activity> systemActivities =
+                            ps != null && ps.pkg != null ? ps.pkg.activities : null;
+                    adjustPriority(systemActivities, intent);
                 }
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
@@ -9924,18 +10294,6 @@
             out.println();
         }
 
-//        List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
-//            final Iterator<ResolveInfo> i = resolveInfoList.iterator();
-//            final List<ResolveInfo> retList = Lists.newArrayList();
-//            while (i.hasNext()) {
-//                final ResolveInfo resolveInfo = i.next();
-//                if (isEnabledLP(resolveInfo.activityInfo)) {
-//                    retList.add(resolveInfo);
-//                }
-//            }
-//            return retList;
-//        }
-
         // Keys are String (activity class name), values are Activity.
         private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
                 = new ArrayMap<ComponentName, PackageParser.Activity>();
@@ -10898,7 +11256,10 @@
                 "isPackageSuspendedForUser for user " + userId);
         synchronized (mPackages) {
             final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
-            return pkgSetting != null && pkgSetting.getSuspended(userId);
+            if (pkgSetting == null) {
+                throw new IllegalArgumentException("Unknown target package: " + packageName);
+            }
+            return pkgSetting.getSuspended(userId);
         }
     }
 
@@ -11284,8 +11645,8 @@
      * @return the current "allow unknown sources" setting
      */
     private int getUnknownSourcesSettings() {
-        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                android.provider.Settings.Global.INSTALL_NON_MARKET_APPS,
+        return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
+                android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS,
                 -1);
     }
 
@@ -12249,8 +12610,6 @@
          * Called after the source arguments are copied. This is used mostly for
          * MoveParams when it needs to read the source file to put it in the
          * destination.
-         *
-         * @return
          */
         int doPostCopy(int uid) {
             return PackageManager.INSTALL_SUCCEEDED;
@@ -15496,17 +15855,14 @@
                 // Otherwise, reset the permission.
                 final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
                 switch (revokeResult) {
-                    case PERMISSION_OPERATION_SUCCESS: {
-                        writeRuntimePermissions = true;
-                    } break;
-
+                    case PERMISSION_OPERATION_SUCCESS:
                     case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
                         writeRuntimePermissions = true;
                         final int appId = ps.appId;
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
+                                killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
                             }
                         });
                     } break;
@@ -16621,6 +16977,21 @@
                 set, comp, userId);
     }
 
+    private @Nullable String getSetupWizardPackageName() {
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
+
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+                MATCH_SYSTEM_ONLY | MATCH_DISABLED_COMPONENTS, UserHandle.myUserId());
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size()
+                    + ": matches=" + matches);
+            return null;
+        }
+    }
+
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index f1b7991..a7512db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -126,4 +126,10 @@
         return value;
     }
 
+    /**
+     * Return the non-profile-guided filter corresponding to the given filter.
+     */
+    public static String getNonProfileGuidedCompilerFilter(String filter) {
+        return DexFile.getNonProfileGuidedCompilerFilter(filter);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 238ce95..8527fd4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -190,7 +190,7 @@
             pw.println("Package " + packageName + " new suspended state: "
                     + mInterface.isPackageSuspendedForUser(packageName, userId));
             return 0;
-        } catch (RemoteException e) {
+        } catch (RemoteException | IllegalArgumentException e) {
             pw.println(e.toString());
             return 1;
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutBackupAgent.java b/services/core/java/com/android/server/pm/ShortcutBackupAgent.java
deleted file mode 100644
index a0fbc37..0000000
--- a/services/core/java/com/android/server/pm/ShortcutBackupAgent.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.pm;
-
-import android.app.backup.BlobBackupHelper;
-
-public class ShortcutBackupAgent extends BlobBackupHelper {
-    private static final String TAG = "ShortcutBackupAgent";
-    private static final int BLOB_VERSION = 1;
-
-    public ShortcutBackupAgent(int currentBlobVersion, String... keys) {
-        super(currentBlobVersion, keys);
-    }
-
-    @Override
-    protected byte[] getBackupPayload(String key) {
-        throw new RuntimeException("not implemented yet"); // todo
-    }
-
-    @Override
-    protected void applyRestoredPayload(String key, byte[] payload) {
-        throw new RuntimeException("not implemented yet"); // todo
-    }
-}
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 7699f30..c6d66fe 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -20,6 +20,10 @@
 import android.content.pm.ShortcutInfo;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -27,6 +31,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -43,15 +48,16 @@
     private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";
     private static final String ATTR_VALUE = "value";
     private static final String ATTR_PACKAGE_NAME = "package-name";
+    private static final String ATTR_PACKAGE_USER_ID = "package-user";
 
     private final int mOwnerUserId;
 
     /**
      * Package name -> IDs.
      */
-    final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
+    final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
 
-    public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
+    private ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
             @UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
         super(launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
         mOwnerUserId = ownerUserId;
@@ -59,7 +65,7 @@
 
     public ShortcutLauncher(@UserIdInt int ownerUserId, @NonNull String packageName,
             @UserIdInt int launcherUserId) {
-        this(launcherUserId, packageName, launcherUserId, null);
+        this(ownerUserId, packageName, launcherUserId, null);
     }
 
     @Override
@@ -67,16 +73,38 @@
         return mOwnerUserId;
     }
 
+    /**
+     * Called when the new package can't receive the backup, due to signature or version mismatch.
+     */
+    @Override
+    protected void onRestoreBlocked(ShortcutService s) {
+        final ArrayList<PackageWithUser> pinnedPackages =
+                new ArrayList<>(mPinnedShortcuts.keySet());
+        mPinnedShortcuts.clear();
+        for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
+            final PackageWithUser pu = pinnedPackages.get(i);
+            s.getPackageShortcutsLocked(pu.packageName, pu.userId)
+                    .refreshPinnedFlags(s);
+        }
+    }
+
+    @Override
+    protected void onRestored(ShortcutService s) {
+        // Nothing to do.
+    }
+
     public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
             @NonNull String packageName, @NonNull List<String> ids) {
         final ShortcutPackage packageShortcuts =
                 s.getPackageShortcutsLocked(packageName, packageUserId);
 
+        final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
+
         final int idSize = ids.size();
         if (idSize == 0) {
-            mPinnedShortcuts.remove(packageName);
+            mPinnedShortcuts.remove(pu);
         } else {
-            final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName);
+            final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
 
             // Pin shortcuts.  Make sure only pin the ones that were visible to the caller.
             // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
@@ -93,7 +121,7 @@
                     newSet.add(id);
                 }
             }
-            mPinnedShortcuts.put(packageName, newSet);
+            mPinnedShortcuts.put(pu, newSet);
         }
         packageShortcuts.refreshPinnedFlags(s);
     }
@@ -101,12 +129,13 @@
     /**
      * Return the pinned shortcut IDs for the publisher package.
      */
-    public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) {
-        return mPinnedShortcuts.get(packageName);
+    public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName,
+            @UserIdInt int packageUserId) {
+        return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
     }
 
-    boolean cleanUpPackage(String packageName) {
-        return mPinnedShortcuts.remove(packageName) != null;
+    boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
+        return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
     }
 
     /**
@@ -126,9 +155,15 @@
         getPackageInfo().saveToXml(out);
 
         for (int i = 0; i < size; i++) {
+            final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
+            if (forBackup && (pu.userId != getOwnerUserId())) {
+                continue; // Target package on a different user, skip. (i.e. work profile)
+            }
+
             out.startTag(null, TAG_PACKAGE);
-            ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME,
-                    mPinnedShortcuts.keyAt(i));
+            ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
+            ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
 
             final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
             final int idSize = ids.size();
@@ -157,8 +192,6 @@
         final ShortcutLauncher ret = new ShortcutLauncher(launcherUserId, launcherPackageName,
                 launcherUserId);
 
-        ShortcutPackageInfo spi = null;
-
         ArraySet<String> ids = null;
         final int outerDepth = parser.getDepth();
         int type;
@@ -172,13 +205,17 @@
             if (depth == outerDepth + 1) {
                 switch (tag) {
                     case ShortcutPackageInfo.TAG_ROOT:
-                        spi = ShortcutPackageInfo.loadFromXml(parser);
+                        ret.getPackageInfo().loadFromXml(parser, fromBackup);
                         continue;
                     case TAG_PACKAGE: {
                         final String packageName = ShortcutService.parseStringAttribute(parser,
                                 ATTR_PACKAGE_NAME);
+                        final int packageUserId = fromBackup ? ownerUserId
+                                : ShortcutService.parseIntAttribute(parser,
+                                ATTR_PACKAGE_USER_ID, ownerUserId);
                         ids = new ArraySet<>();
-                        ret.mPinnedShortcuts.put(packageName, ids);
+                        ret.mPinnedShortcuts.put(
+                                PackageWithUser.of(packageUserId, packageName), ids);
                         continue;
                     }
                 }
@@ -186,17 +223,17 @@
             if (depth == outerDepth + 2) {
                 switch (tag) {
                     case TAG_PIN: {
-                        ids.add(ShortcutService.parseStringAttribute(parser,
-                                ATTR_VALUE));
+                        if (ids == null) {
+                            Slog.w(TAG, TAG_PIN + " in invalid place");
+                        } else {
+                            ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
+                        }
                         continue;
                     }
                 }
             }
             ShortcutService.warnForInvalidTag(depth, tag);
         }
-        if (spi != null) {
-            ret.replacePackageInfo(spi);
-        }
         return ret;
     }
 
@@ -208,6 +245,8 @@
         pw.print(getPackageName());
         pw.print("  Package user: ");
         pw.print(getPackageUserId());
+        pw.print("  Owner user: ");
+        pw.print(getOwnerUserId());
         pw.println();
 
         getPackageInfo().dump(s, pw, prefix + "  ");
@@ -217,10 +256,14 @@
         for (int i = 0; i < size; i++) {
             pw.println();
 
+            final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
+
             pw.print(prefix);
             pw.print("  ");
             pw.print("Package: ");
-            pw.println(mPinnedShortcuts.keyAt(i));
+            pw.print(pu.packageName);
+            pw.print("  User: ");
+            pw.println(pu.userId);
 
             final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
             final int idSize = ids.size();
@@ -233,4 +276,9 @@
             }
         }
     }
+
+    @VisibleForTesting
+    ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
+        return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 5916202..1076a7a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -26,6 +26,8 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -34,6 +36,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.function.Predicate;
 
@@ -83,7 +86,7 @@
      */
     private long mLastResetTime;
 
-    public ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
+    private ShortcutPackage(int packageUserId, String packageName, ShortcutPackageInfo spi) {
         super(packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
     }
 
@@ -97,6 +100,19 @@
         return getPackageUserId();
     }
 
+    @Override
+    protected void onRestoreBlocked(ShortcutService s) {
+        // Can't restore due to version/signature mismatch.  Remove all shortcuts.
+        mShortcuts.clear();
+    }
+
+    @Override
+    protected void onRestored(ShortcutService s) {
+        // Because some launchers may not have been restored (e.g. allowBackup=false),
+        // we need to re-calculate the pinned shortcuts.
+        refreshPinnedFlags(s);
+    }
+
     /**
      * Note this does *not* provide a correct view to the calling launcher.
      */
@@ -229,20 +245,26 @@
                 s.getUserShortcutsLocked(getPackageUserId()).getAllLaunchers();
 
         for (int l = launchers.size() - 1; l >= 0; l--) {
+            // Note even if a launcher that hasn't been installed can still pin shortcuts.
+
             final ShortcutLauncher launcherShortcuts = launchers.valueAt(l);
             final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
-                    getPackageName());
+                    getPackageName(), getPackageUserId());
 
             if (pinned == null || pinned.size() == 0) {
                 continue;
             }
             for (int i = pinned.size() - 1; i >= 0; i--) {
-                final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i));
+                final String id = pinned.valueAt(i);
+                final ShortcutInfo si = mShortcuts.get(id);
                 if (si == null) {
-                    s.wtf("Shortcut not found");
-                } else {
-                    si.addFlags(ShortcutInfo.FLAG_PINNED);
+                    // This happens if a launcher pinned shortcuts from this package, then backup&
+                    // restored, but this package doesn't allow backing up.
+                    // In that case the launcher ends up having a dangling pinned shortcuts.
+                    // That's fine, when the launcher is restored, we'll fix it.
+                    continue;
                 }
+                si.addFlags(ShortcutInfo.FLAG_PINNED);
             }
         }
 
@@ -312,11 +334,15 @@
     public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
             @Nullable Predicate<ShortcutInfo> query, int cloneFlag,
             @Nullable String callingLauncher, int launcherUserId) {
+        if (getPackageInfo().isShadow()) {
+            // Restored and the app not installed yet, so don't return any.
+            return;
+        }
 
         // Set of pinned shortcuts by the calling launcher.
         final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
-                : s.getLauncherShortcuts(callingLauncher, getPackageUserId(), launcherUserId)
-                    .getPinnedShortcutIds(getPackageName());
+                : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
+                    .getPinnedShortcutIds(getPackageName(), getPackageUserId());
 
         for (int i = 0; i < mShortcuts.size(); i++) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
@@ -328,7 +354,8 @@
                     || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
             if (!si.isDynamic()) {
                 if (!si.isPinned()) {
-                    s.wtf("Shortcut not pinned here");
+                    s.wtf("Shortcut not pinned: package " + getPackageName()
+                            + ", user=" + getPackageUserId() + ", id=" + si.getId());
                     continue;
                 }
                 if (!isPinnedByCaller) {
@@ -479,7 +506,6 @@
                 ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
         ret.mLastResetTime =
                 ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
-        ShortcutPackageInfo spi = null;
 
         final int outerDepth = parser.getDepth();
         int type;
@@ -493,7 +519,7 @@
             if (depth == outerDepth + 1) {
                 switch (tag) {
                     case ShortcutPackageInfo.TAG_ROOT:
-                        spi = ShortcutPackageInfo.loadFromXml(parser);
+                        ret.getPackageInfo().loadFromXml(parser, fromBackup);
                         continue;
                     case TAG_SHORTCUT:
                         final ShortcutInfo si = parseShortcut(parser, packageName);
@@ -505,9 +531,6 @@
             }
             ShortcutService.warnForInvalidTag(depth, tag);
         }
-        if (spi != null) {
-            ret.replacePackageInfo(spi);
-        }
         return ret;
     }
 
@@ -567,4 +590,9 @@
                 intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
                 iconRes, bitmapPath);
     }
+
+    @VisibleForTesting
+    List<ShortcutInfo> getAllShortcutsForTest() {
+        return new ArrayList<>(mShortcuts.values());
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 5f706b8..2c45890 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -67,10 +67,6 @@
         return mIsShadow;
     }
 
-    public boolean isInstalled() {
-        return !mIsShadow;
-    }
-
     public void setShadow(boolean shadow) {
         mIsShadow = shadow;
     }
@@ -79,14 +75,24 @@
         return mVersionCode;
     }
 
-    public boolean canRestoreTo(PackageInfo target) {
+    public boolean hasSignatures() {
+        return mSigHashes.size() > 0;
+    }
+
+    public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
+        if (!s.shouldBackupApp(target)) {
+            // "allowBackup" was true when backed up, but now false.
+            Slog.w(TAG, "Can't restore: package no longer allows backup");
+            return false;
+        }
         if (target.versionCode < mVersionCode) {
-            Slog.w(TAG, String.format("Package current version %d < backed up version %d",
+            Slog.w(TAG, String.format(
+                    "Can't restore: package current version %d < backed up version %d",
                     target.versionCode, mVersionCode));
             return false;
         }
         if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
-            Slog.w(TAG, "Package signature mismtach");
+            Slog.w(TAG, "Can't restore: Package signature mismatch");
             return false;
         }
         return true;
@@ -106,6 +112,11 @@
     }
 
     public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
+        if (mIsShadow) {
+            s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
+                    + ", user=" + pkg.getOwnerUserId());
+            return;
+        }
         // Note use mUserId here, rather than userId.
         final PackageInfo pi = s.getPackageInfoWithSignatures(
                 pkg.getPackageName(), pkg.getPackageUserId());
@@ -132,15 +143,17 @@
         out.endTag(null, TAG_ROOT);
     }
 
-    public static ShortcutPackageInfo loadFromXml(XmlPullParser parser)
+    public void loadFromXml(XmlPullParser parser, boolean fromBackup)
             throws IOException, XmlPullParserException {
 
         final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
-        final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
+
+        // When restoring from backup, it's always shadow.
+        final boolean shadow =
+                fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
 
         final ArrayList<byte[]> hashes = new ArrayList<>();
 
-
         final int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -163,7 +176,11 @@
             }
             ShortcutService.warnForInvalidTag(depth, tag);
         }
-        return new ShortcutPackageInfo(versionCode, hashes, shadow);
+
+        // Successfully loaded; replace the feilds.
+        mVersionCode = versionCode;
+        mIsShadow = shadow;
+        mSigHashes = hashes;
     }
 
     public void dump(ShortcutService s, PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index de2709d..f31dd17 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -16,6 +16,8 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.util.Slog;
 
 import com.android.internal.util.Preconditions;
 
@@ -25,10 +27,12 @@
 import java.io.IOException;
 
 abstract class ShortcutPackageItem {
+    private static final String TAG = ShortcutService.TAG;
+
     private final int mPackageUserId;
     private final String mPackageName;
 
-    private ShortcutPackageInfo mPackageInfo;
+    private final ShortcutPackageInfo mPackageInfo;
 
     protected ShortcutPackageItem(int packageUserId, @NonNull String packageName,
             @NonNull ShortcutPackageInfo packageInfo) {
@@ -61,25 +65,62 @@
         return mPackageInfo;
     }
 
-    /**
-     * Should be only used when loading from a file.o
-     */
-    protected void replacePackageInfo(@NonNull ShortcutPackageInfo packageInfo) {
-        mPackageInfo = Preconditions.checkNotNull(packageInfo);
-    }
-
     public void refreshPackageInfoAndSave(ShortcutService s) {
+        if (mPackageInfo.isShadow()) {
+            return; // Don't refresh for shadow user.
+        }
         mPackageInfo.refresh(s, this);
         s.scheduleSaveUser(getOwnerUserId());
     }
 
-    public void ensureNotShadowAndSave(ShortcutService s) {
-        if (mPackageInfo.isShadow()) {
-            mPackageInfo.setShadow(false);
-            s.scheduleSaveUser(getOwnerUserId());
+    public void attemptToRestoreIfNeededAndSave(ShortcutService s) {
+        if (!mPackageInfo.isShadow()) {
+            return; // Already installed, nothing to do.
         }
+        if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
+            if (ShortcutService.DEBUG) {
+                Slog.d(TAG, String.format("Package still not installed: %s user=%d",
+                        mPackageName, mPackageUserId));
+            }
+            return; // Not installed, no need to restore yet.
+        }
+        if (!mPackageInfo.hasSignatures()) {
+            s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
+                    + " but signatures not found in the restore data.");
+            onRestoreBlocked(s);
+            return;
+        }
+
+        final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+        if (!mPackageInfo.canRestoreTo(s, pi)) {
+            // Package is now installed, but can't restore.  Let the subclass do the cleanup.
+            onRestoreBlocked(s);
+            return;
+        }
+        if (ShortcutService.DEBUG) {
+            Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
+                    mPackageUserId, getOwnerUserId()));
+        }
+
+        onRestored(s);
+
+        // Now the package is not shadow.
+        mPackageInfo.setShadow(false);
+
+        s.scheduleSaveUser(mPackageUserId);
     }
 
+    /**
+     * Called when the new package can't be restored because it has a lower version number
+     * or different signatures.
+     */
+    protected abstract void onRestoreBlocked(ShortcutService s);
+
+    /**
+     * Called when the new package is successfully restored.
+     */
+    protected abstract void onRestored(ShortcutService s);
+
     public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException;
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 76a2dfa..5c1e7a8 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -46,6 +46,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
@@ -101,6 +102,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -112,17 +114,16 @@
  *
  * - Scan and remove orphan bitmaps (just in case).
  *
- * - Backup & restore
- *
  * - Detect when already registered instances are passed to APIs again, which might break
  *   internal bitmap handling.
+ *
+ * - Add more call stats.
  */
 public class ShortcutService extends IShortcutService.Stub {
     static final String TAG = "ShortcutService";
 
     static final boolean DEBUG = false; // STOPSHIP if true
     static final boolean DEBUG_LOAD = false; // STOPSHIP if true
-    static final boolean ENABLE_DEBUG_COMMAND = true; // STOPSHIP if true
 
     @VisibleForTesting
     static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
@@ -262,6 +263,26 @@
             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
             | PackageManager.MATCH_UNINSTALLED_PACKAGES;
 
+    // Stats
+    @VisibleForTesting
+    interface Stats {
+        int GET_DEFAULT_HOME = 0;
+        int GET_PACKAGE_INFO = 1;
+        int GET_PACKAGE_INFO_WITH_SIG = 2;
+        int GET_APPLICATION_INFO = 3;
+        int LAUNCHER_PERMISSION_CHECK = 4;
+
+        int COUNT = LAUNCHER_PERMISSION_CHECK + 1;
+    }
+
+    final Object mStatLock = new Object();
+
+    @GuardedBy("mStatLock")
+    private final int[] mCountStats = new int[Stats.COUNT];
+
+    @GuardedBy("mStatLock")
+    private final long[] mDurationStats = new long[Stats.COUNT];
+
     public ShortcutService(Context context) {
         this(context, BackgroundThread.get().getLooper());
     }
@@ -278,6 +299,13 @@
         mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
     }
 
+    void logDurationStat(int statId, long start) {
+        synchronized (mStatLock) {
+            mCountStats[statId]++;
+            mDurationStats[statId] += (System.currentTimeMillis() - start);
+        }
+    }
+
     /**
      * System service lifecycle.
      */
@@ -822,7 +850,7 @@
 
     @GuardedBy("mLock")
     @NonNull
-    boolean isUserLoadedLocked(@UserIdInt int userId) {
+    private boolean isUserLoadedLocked(@UserIdInt int userId) {
         return mUsers.get(userId) != null;
     }
 
@@ -841,19 +869,27 @@
         return userPackages;
     }
 
+    void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
+        for (int i = mUsers.size() - 1; i >= 0; i--) {
+            c.accept(mUsers.valueAt(i));
+        }
+    }
+
     /** Return the per-user per-package state. */
     @GuardedBy("mLock")
     @NonNull
     ShortcutPackage getPackageShortcutsLocked(
             @NonNull String packageName, @UserIdInt int userId) {
-        return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
+        return getUserShortcutsLocked(userId).getPackageShortcuts(this, packageName);
     }
 
     @GuardedBy("mLock")
     @NonNull
-    ShortcutLauncher getLauncherShortcuts(
-            @NonNull String packageName, @UserIdInt int userId, @UserIdInt int launcherUserId) {
-        return getUserShortcutsLocked(userId).getLauncherShortcuts(packageName, launcherUserId);
+    ShortcutLauncher getLauncherShortcutsLocked(
+            @NonNull String packageName, @UserIdInt int ownerUserId,
+            @UserIdInt int launcherUserId) {
+        return getUserShortcutsLocked(ownerUserId)
+                .getLauncherShortcuts(this, packageName, launcherUserId);
     }
 
     // === Caller validation ===
@@ -1212,8 +1248,6 @@
         synchronized (mLock) {
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
 
-            ps.ensureNotShadowAndSave(this);
-
             // Throttling.
             if (!ps.tryApiCall(this)) {
                 return false;
@@ -1249,8 +1283,6 @@
         synchronized (mLock) {
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
 
-            ps.ensureNotShadowAndSave(this);
-
             // Throttling.
             if (!ps.tryApiCall(this)) {
                 return false;
@@ -1288,8 +1320,6 @@
         synchronized (mLock) {
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
 
-            ps.ensureNotShadowAndSave(this);
-
             // Throttling.
             if (!ps.tryApiCall(this)) {
                 return false;
@@ -1422,15 +1452,17 @@
     @VisibleForTesting
     boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
         synchronized (mLock) {
-            long start = System.currentTimeMillis();
+            final long start = System.currentTimeMillis();
 
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
             final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
 
             // Default launcher from package manager.
+            final long startGetHomeActivitiesAsUser = System.currentTimeMillis();
             final ComponentName defaultLauncher = injectPackageManagerInternal()
                     .getHomeActivitiesAsUser(allHomeCandidates, userId);
+            logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
 
             ComponentName detected;
             if (defaultLauncher != null) {
@@ -1473,10 +1505,8 @@
                     lastPriority = ri.priority;
                 }
             }
-            final long end = System.currentTimeMillis();
-            if (DEBUG) {
-                Slog.v(TAG, String.format("hasShortcutPermission took %d ms", end - start));
-            }
+            logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
+
             if (detected != null) {
                 if (DEBUG) {
                     Slog.v(TAG, "Detected launcher: " + detected);
@@ -1492,10 +1522,17 @@
 
     // === House keeping ===
 
+    /**
+     * Remove all the information associated with a package.  This will really remove all the
+     * information, including the restore information (i.e. it'll remove packages even if they're
+     * shadow).
+     */
     @VisibleForTesting
     void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) {
-
-        // TODO Don't remove shadow packages' information.
+        if (isPackageInstalled(packageName, packageUserId)) {
+            wtf("Package " + packageName + " is still installed for user " + packageUserId);
+            return;
+        }
 
         final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
 
@@ -1504,7 +1541,7 @@
 
         // First, remove the package from the package list (if the package is a publisher).
         if (packageUserId == owningUserId) {
-            if (mUser.getPackages().remove(packageName) != null) {
+            if (mUser.removePackage(packageName) != null) {
                 doNotify = true;
             }
         }
@@ -1515,12 +1552,12 @@
         // Then remove pinned shortcuts from all launchers.
         final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers();
         for (int i = launchers.size() - 1; i >= 0; i--) {
-            launchers.valueAt(i).cleanUpPackage(packageName);
+            launchers.valueAt(i).cleanUpPackage(packageName, packageUserId);
         }
         // Now there may be orphan shortcuts because we removed pinned shortucts at the previous
         // step.  Remove them too.
-        for (int i = mUser.getPackages().size() - 1; i >= 0; i--) {
-            mUser.getPackages().valueAt(i).refreshPinnedFlags(this);
+        for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) {
+            mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this);
         }
 
         scheduleSaveUser(owningUserId);
@@ -1539,6 +1576,7 @@
      * Entry point from {@link LauncherApps}.
      */
     private class LocalService extends ShortcutServiceInternal {
+
         @Override
         public List<ShortcutInfo> getShortcuts(int launcherUserId,
                 @NonNull String callingPackage, long changedSince,
@@ -1551,13 +1589,16 @@
                             : ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
 
             synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
                 if (packageName != null) {
                     getShortcutsInnerLocked(launcherUserId,
                             callingPackage, packageName, changedSince,
                             componentName, queryFlags, userId, ret, cloneFlag);
                 } else {
                     final ArrayMap<String, ShortcutPackage> packages =
-                            getUserShortcutsLocked(userId).getPackages();
+                            getUserShortcutsLocked(userId).getAllPackages();
                     for (int i = packages.size() - 1; i >= 0; i--) {
                         getShortcutsInnerLocked(launcherUserId,
                                 callingPackage, packages.keyAt(i), changedSince,
@@ -1601,6 +1642,9 @@
             final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
             final ArraySet<String> idSet = new ArraySet<>(ids);
             synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
                 getPackageShortcutsLocked(packageName, userId).findAll(
                         ShortcutService.this, ret,
                         (ShortcutInfo si) -> idSet.contains(si.getId()),
@@ -1616,13 +1660,16 @@
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
             synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
                 final ShortcutInfo si = getShortcutInfoLocked(
                         launcherUserId, callingPackage, packageName, shortcutId, userId);
                 return si != null && si.isPinned();
             }
         }
 
-        public ShortcutInfo getShortcutInfoLocked(
+        private ShortcutInfo getShortcutInfoLocked(
                 int launcherUserId, @NonNull String callingPackage,
                 @NonNull String packageName, @NonNull String shortcutId, int userId) {
             Preconditions.checkStringNotEmpty(packageName, "packageName");
@@ -1646,9 +1693,8 @@
 
             synchronized (mLock) {
                 final ShortcutLauncher launcher =
-                        getLauncherShortcuts(callingPackage, userId, launcherUserId);
-
-                launcher.ensureNotShadowAndSave(ShortcutService.this);
+                        getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
+                launcher.attemptToRestoreIfNeededAndSave(ShortcutService.this);
 
                 launcher.pinShortcuts(
                         ShortcutService.this, userId, packageName, shortcutIds);
@@ -1665,6 +1711,9 @@
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
 
             synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
                 // Make sure the shortcut is actually visible to the launcher.
                 final ShortcutInfo si = getShortcutInfoLocked(
                         launcherUserId, callingPackage, packageName, shortcutId, userId);
@@ -1690,6 +1739,9 @@
             Preconditions.checkNotNull(shortcut, "shortcut");
 
             synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
                 final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
                         shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
                 return (shortcutInfo != null && shortcutInfo.hasIconResource())
@@ -1704,6 +1756,9 @@
             Preconditions.checkNotNull(shortcutIn, "shortcut");
 
             synchronized (mLock) {
+                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+
                 final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
                         shortcutIn.getPackageName(), userId).findShortcutById(shortcutIn.getId());
                 if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
@@ -1757,28 +1812,28 @@
      * perform cleanup.
      */
     @VisibleForTesting
-    void cleanupGonePackages(@UserIdInt int userId) {
+    void cleanupGonePackages(@UserIdInt int ownerUserId) {
         if (DEBUG) {
-            Slog.d(TAG, "cleanupGonePackages() userId=" + userId);
+            Slog.d(TAG, "cleanupGonePackages() ownerUserId=" + ownerUserId);
         }
         final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
 
         synchronized (mLock) {
-            final ShortcutUser user = getUserShortcutsLocked(userId);
+            final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
 
             user.forAllPackageItems(spi -> {
                 if (spi.getPackageInfo().isShadow()) {
                     return; // Don't delete shadow information.
                 }
                 if (isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
-                    return;
+                    return; // Package not gone.
                 }
                 gonePackages.add(PackageWithUser.of(spi));
             });
             if (gonePackages.size() > 0) {
                 for (int i = gonePackages.size() - 1; i >= 0; i--) {
                     final PackageWithUser pu = gonePackages.get(i);
-                    cleanUpPackageLocked(pu.packageName, userId, pu.userId);
+                    cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
                 }
             }
         }
@@ -1789,7 +1844,8 @@
             Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
         }
         synchronized (mLock) {
-            getUserShortcutsLocked(userId).unshadowPackage(this, packageName, userId);
+            forEachLoadedUserLocked(user ->
+                    user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
         }
     }
 
@@ -1798,18 +1854,20 @@
             Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
                     packageName, userId));
         }
-
         synchronized (mLock) {
-            getUserShortcutsLocked(userId).unshadowPackage(this, packageName, userId);
+            forEachLoadedUserLocked(user ->
+                    user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
         }
     }
 
-    private void handlePackageRemoved(String packageName, @UserIdInt int userId) {
+    private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
         if (DEBUG) {
-            Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName, userId));
+            Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
+                    packageUserId));
         }
         synchronized (mLock) {
-            cleanUpPackageLocked(packageName, userId, userId);
+            forEachLoadedUserLocked(user ->
+                cleanUpPackageLocked(packageName, user.getUserId(), packageUserId));
         }
     }
 
@@ -1836,6 +1894,7 @@
     @VisibleForTesting
     PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
             boolean getSignatures) {
+        final long start = System.currentTimeMillis();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
@@ -1847,11 +1906,16 @@
             return null;
         } finally {
             injectRestoreCallingIdentity(token);
+
+            logDurationStat(
+                    (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO),
+                    start);
         }
     }
 
     @VisibleForTesting
     ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+        final long start = System.currentTimeMillis();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
@@ -1861,6 +1925,8 @@
             return null;
         } finally {
             injectRestoreCallingIdentity(token);
+
+            logDurationStat(Stats.GET_APPLICATION_INFO, start);
         }
     }
 
@@ -1869,7 +1935,7 @@
         return (ai != null) && ((ai.flags & flags) == flags);
     }
 
-    private boolean isPackageInstalled(String packageName, int userId) {
+    boolean isPackageInstalled(String packageName, int userId) {
         return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
     }
 
@@ -1879,8 +1945,12 @@
         return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
     }
 
+    boolean shouldBackupApp(PackageInfo pi) {
+        return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+    }
+
     @Override
-    public byte[] getBackupPayload(@UserIdInt int userId) throws RemoteException {
+    public byte[] getBackupPayload(@UserIdInt int userId) {
         enforceSystem();
         if (DEBUG) {
             Slog.d(TAG, "Backing up user " + userId);
@@ -1908,7 +1978,7 @@
     }
 
     @Override
-    public void applyRestore(byte[] payload, @UserIdInt int userId) throws RemoteException {
+    public void applyRestore(byte[] payload, @UserIdInt int userId) {
         enforceSystem();
         if (DEBUG) {
             Slog.d(TAG, "Restoring user " + userId);
@@ -1923,6 +1993,15 @@
         }
         synchronized (mLock) {
             mUsers.put(userId, user);
+
+            // Then purge all the save images.
+            final File bitmapPath = getUserBitmapFilePath(userId);
+            final boolean success = FileUtils.deleteContents(bitmapPath);
+            if (!success) {
+                Slog.w(TAG, "Failed to delete " + bitmapPath);
+            }
+
+            saveUserLocked(userId);
         }
     }
 
@@ -1974,9 +2053,19 @@
             pw.print("  Icon format: ");
             pw.print(mIconPersistFormat);
             pw.print("  Icon quality: ");
-            pw.print(mIconPersistQuality);
+            pw.println(mIconPersistQuality);
             pw.println();
 
+            pw.println("  Stats:");
+            synchronized (mStatLock) {
+                final String p = "     ";
+                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
+                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
+
+                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
+                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
+                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
+            }
 
             for (int i = 0; i < mUsers.size(); i++) {
                 pw.println();
@@ -1991,6 +2080,15 @@
         return tobj.format("%Y-%m-%d %H:%M:%S");
     }
 
+    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+        pw.print(prefix);
+        final int count = mCountStats[statId];
+        final long dur = mDurationStats[statId];
+        pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
+                label, count, dur,
+                (count == 0 ? 0 : ((double) dur) / count)));
+    }
+
     // === Shell support ===
 
     @Override
@@ -2061,6 +2159,9 @@
                     case "refresh-default-launcher":
                         handleRefreshDefaultLauncher();
                         break;
+                    case "unload-user":
+                        handleUnloadUser();
+                        break;
                     default:
                         return handleDefaultCommands(cmd);
                 }
@@ -2098,6 +2199,10 @@
             pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]");
             pw.println("    Refresh the cached default launcher");
             pw.println();
+            pw.println("cmd shortcut unload-user [--user USER_ID]");
+            pw.println("    Unload a user from the memory");
+            pw.println("    (This should not affect any observable behavior)");
+            pw.println();
         }
 
         private int handleResetThrottling() throws CommandException {
@@ -2169,6 +2274,12 @@
             clearLauncher();
             showLauncher();
         }
+
+        private void handleUnloadUser() throws CommandException {
+            parseOptions(/* takeUser =*/ true);
+
+            ShortcutService.this.handleCleanupUser(mUserId);
+        }
     }
 
     // === Unit test support ===
@@ -2202,9 +2313,10 @@
     }
 
     final void wtf(String message) {
-        Slog.wtf(TAG, message, /* exception= */ null);
+        wtf( message, /* exception= */ null);
     }
 
+    // Injection point.
     void wtf(String message, Exception e) {
         Slog.wtf(TAG, message, e);
     }
@@ -2275,7 +2387,7 @@
             final ShortcutUser user = mUsers.get(userId);
             if (user == null) return null;
 
-            final ShortcutPackage pkg = user.getPackages().get(packageName);
+            final ShortcutPackage pkg = user.getAllPackages().get(packageName);
             if (pkg == null) return null;
 
             return pkg.findShortcutById(shortcutId);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 487558f..593f607 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -53,8 +53,8 @@
             this.packageName = Preconditions.checkNotNull(packageName);
         }
 
-        public static PackageWithUser of(int launcherUserId, String packageName) {
-            return new PackageWithUser(launcherUserId, packageName);
+        public static PackageWithUser of(int userId, String packageName) {
+            return new PackageWithUser(userId, packageName);
         }
 
         public static PackageWithUser of(ShortcutPackageItem spi) {
@@ -78,12 +78,12 @@
 
         @Override
         public String toString() {
-            return String.format("{Launcher: %d, %s}", userId, packageName);
+            return String.format("{Package: %d, %s}", userId, packageName);
         }
     }
 
     @UserIdInt
-    final int mUserId;
+    private final int mUserId;
 
     private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
 
@@ -95,10 +95,18 @@
         mUserId = userId;
     }
 
-    public ArrayMap<String, ShortcutPackage> getPackages() {
+    public int getUserId() {
+        return mUserId;
+    }
+
+    public ArrayMap<String, ShortcutPackage> getAllPackages() {
         return mPackages;
     }
 
+    public ShortcutPackage removePackage(@NonNull String packageName) {
+        return mPackages.remove(packageName);
+    }
+
     public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
         return mLaunchers;
     }
@@ -113,22 +121,26 @@
         return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
     }
 
-    public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
+    public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) {
         ShortcutPackage ret = mPackages.get(packageName);
         if (ret == null) {
             ret = new ShortcutPackage(mUserId, packageName);
             mPackages.put(packageName, ret);
+        } else {
+            ret.attemptToRestoreIfNeededAndSave(s);
         }
         return ret;
     }
 
-    public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
+    public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName,
             @UserIdInt int launcherUserId) {
         final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
         ShortcutLauncher ret = mLaunchers.get(key);
         if (ret == null) {
             ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
             mLaunchers.put(key, ret);
+        } else {
+            ret.attemptToRestoreIfNeededAndSave(s);
         }
         return ret;
     }
@@ -148,14 +160,6 @@
         }
     }
 
-    public void unshadowPackage(ShortcutService s, @NonNull String packageName,
-            @UserIdInt int packageUserId) {
-        forPackageItem(packageName, packageUserId, spi -> {
-            Slog.i(TAG, String.format("Restoring for %s, user=%d", packageName, packageUserId));
-            spi.ensureNotShadowAndSave(s);
-        });
-    }
-
     public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
             Consumer<ShortcutPackageItem> callback) {
         forAllPackageItems(spi -> {
@@ -166,6 +170,13 @@
         });
     }
 
+    public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
+            @UserIdInt int packageUserId) {
+        forPackageItem(packageName, packageUserId, spi -> {
+            spi.attemptToRestoreIfNeededAndSave(s);
+        });
+    }
+
     public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException {
         out.startTag(null, TAG_ROOT);
@@ -229,7 +240,7 @@
                                 s, parser, userId, fromBackup);
 
                         // Don't use addShortcut(), we don't need to save the icon.
-                        ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
+                        ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
                         continue;
                     }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7f0da1e..3ff46ac 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1941,6 +1941,7 @@
                     long now = System.currentTimeMillis();
                     userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
                     userInfo.partial = true;
+                    userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
                     userData = new UserData();
                     userData.info = userInfo;
                     mUsers.put(userId, userData);
@@ -2281,6 +2282,7 @@
             if (restrictions == null || restrictions.isEmpty()) {
                 cleanAppRestrictionsForPackage(packageName, userId);
             } else {
+                restrictions.setDefusable(true);
                 // Write the restrictions to XML
                 writeApplicationRestrictionsLP(packageName, restrictions, userId);
             }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 574faa0..14d0457 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,7 +18,6 @@
 
 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.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
@@ -38,7 +37,6 @@
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 
-import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerInternal;
@@ -3109,10 +3107,8 @@
                 return -1;
             }
         } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
-            if (down) {
-                if (repeatCount == 0) {
-                    toggleKeyboardShortcutsMenu(event.getDeviceId());
-                }
+            if (down && repeatCount == 0 && !isKeyguardLocked()) {
+                toggleKeyboardShortcutsMenu(event.getDeviceId());
             }
         } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
             if (down) {
@@ -4647,7 +4643,7 @@
         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
         // Also, we don't allow windows in multi-window mode to extend out of the screen.
         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR
-                && !win.inMultiWindowMode()) {
+                && !win.isInMultiWindowMode()) {
             df.left = df.top = -10000;
             df.right = df.bottom = 10000;
             if (attrs.type != TYPE_WALLPAPER) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ff5a0f9..7570960 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -538,7 +538,10 @@
     @Override
     public void onBootPhase(int phase) {
         synchronized (mLock) {
-            if (phase == PHASE_BOOT_COMPLETED) {
+            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+                incrementBootCount();
+
+            } else if (phase == PHASE_BOOT_COMPLETED) {
                 final long now = SystemClock.uptimeMillis();
                 mBootCompleted = true;
                 mDirty |= DIRTY_BOOT_COMPLETED;
@@ -553,8 +556,6 @@
                     }
                 }
                 mBootCompletedRunnables = null;
-
-                incrementBootCount();
             }
         }
     }
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 1363fb9..eb926c1 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -227,10 +227,11 @@
         return userIds;
     }
 
-    private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+    public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
+            String serviceName, String permissionName) {
+
         ArraySet<ComponentName> installed = new ArraySet<>();
-        PackageManager pm = mContext.getPackageManager();
-        Intent queryIntent = new Intent(mServiceName);
+        Intent queryIntent = new Intent(serviceName);
         List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                 queryIntent,
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -241,10 +242,10 @@
                 ServiceInfo info = resolveInfo.serviceInfo;
 
                 ComponentName component = new ComponentName(info.packageName, info.name);
-                if (!mServicePermission.equals(info.permission)) {
+                if (!permissionName.equals(info.permission)) {
                     Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
                             + ": it does not require the permission "
-                            + mServicePermission);
+                            + permissionName);
                     continue;
                 }
                 installed.add(component);
@@ -253,6 +254,11 @@
         return installed;
     }
 
+    private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
+        return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
+                mServicePermission);
+    }
+
     private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
             int userId) {
         final ContentResolver cr = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index aa6f59e..c572e76 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -16,16 +16,23 @@
 package com.android.server.vr;
 
 import android.app.AppOpsManager;
+import android.app.NotificationManager;
 import android.annotation.NonNull;
-import android.content.Context;
 import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
 import android.service.vr.IVrListener;
 import android.service.vr.VrListenerService;
 import android.util.ArraySet;
@@ -38,7 +45,9 @@
 import com.android.server.utils.ManagedApplicationService;
 import com.android.server.utils.ManagedApplicationService.BinderChecker;
 
+import java.lang.StringBuilder;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Objects;
 import java.util.Set;
 
@@ -53,8 +62,8 @@
  *  hardware/libhardware/modules/vr
  * <p/>
  * In general applications may enable or disable VR mode by calling
- * {@link android.app.Activity#setVrMode)}.  An application may also implement a service to be run
- * while in VR mode by implementing {@link android.service.vr.VrListenerService}.
+ * {@link android.app.Activity#setVrModeEnabled)}.  An application may also implement a service to
+ * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
  *
  * @see {@link android.service.vr.VrListenerService}
  * @see {@link com.android.server.vr.VrManagerInternal}
@@ -74,13 +83,18 @@
     private final IBinder mOverlayToken = new Binder();
 
     // State protected by mLock
-    private boolean mVrModeEnabled = false;
+    private boolean mVrModeEnabled;
     private final Set<VrStateListener> mListeners = new ArraySet<>();
     private EnabledComponentsObserver mComponentObserver;
     private ManagedApplicationService mCurrentVrService;
     private Context mContext;
     private ComponentName mCurrentVrModeComponent;
     private int mCurrentVrModeUser;
+    private boolean mWasDefaultGranted;
+    private boolean mGuard;
+    private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
+    private String mPreviousNotificationPolicyAccessPackage;
+    private String mPreviousManageOverlayPackage;
 
     private static final BinderChecker sBinderChecker = new BinderChecker() {
         @Override
@@ -239,62 +253,271 @@
      *
      * @return {@code true} if the component/user combination specified is valid.
      */
-    private boolean updateCurrentVrServiceLocked(boolean enabled,
-            @NonNull ComponentName component, int userId, ComponentName calling) {
+    private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
+            int userId, ComponentName calling) {
 
         boolean sendUpdatedCaller = false;
+        final long identity = Binder.clearCallingIdentity();
+        try {
 
-        boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
-                EnabledComponentsObserver.NO_ERROR);
+            boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
+                    EnabledComponentsObserver.NO_ERROR);
 
-        // Always send mode change events.
-        changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
+            // Always send mode change events.
+            changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
 
-        if (!enabled || !validUserComponent) {
-            // Unbind whatever is running
-            if (mCurrentVrService != null) {
-                Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
-                        mCurrentVrService.getUserId());
-                mCurrentVrService.disconnect();
-                mCurrentVrService = null;
-            }
-        } else {
-            if (mCurrentVrService != null) {
-                // Unbind any running service that doesn't match the component/user selection
-                if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+            if (!enabled || !validUserComponent) {
+                // Unbind whatever is running
+                if (mCurrentVrService != null) {
                     Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
-                        mCurrentVrService.getUserId());
+                            mCurrentVrService.getUserId());
+                    mCurrentVrService.disconnect();
+                    disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                            new UserHandle(mCurrentVrService.getUserId()));
+                    mCurrentVrService = null;
+                }
+            } else {
+                if (mCurrentVrService != null) {
+                    // Unbind any running service that doesn't match the component/user selection
+                    if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
+                        Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
+                                " for user " + mCurrentVrService.getUserId());
+                        disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                                new UserHandle(mCurrentVrService.getUserId()));
+                        createAndConnectService(component, userId);
+                        enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                                new UserHandle(mCurrentVrService.getUserId()));
+                        sendUpdatedCaller = true;
+                    }
+                    // The service with the correct component/user is bound
+                } else {
+                    // Nothing was previously running, bind a new service
                     createAndConnectService(component, userId);
+                    enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
+                            new UserHandle(mCurrentVrService.getUserId()));
                     sendUpdatedCaller = true;
                 }
-                // The service with the correct component/user is bound
-            } else {
-                // Nothing was previously running, bind a new service
-                createAndConnectService(component, userId);
+            }
+
+            if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent))  {
+                mCurrentVrModeComponent = calling;
+                mCurrentVrModeUser = userId;
                 sendUpdatedCaller = true;
             }
+
+            if (mCurrentVrService != null && sendUpdatedCaller) {
+                final ComponentName c = mCurrentVrModeComponent;
+                mCurrentVrService.sendEvent(new PendingEvent() {
+                    @Override
+                    public void runEvent(IInterface service) throws RemoteException {
+                        IVrListener l = (IVrListener) service;
+                        l.focusedActivityChanged(c);
+                    }
+                });
+            }
+
+            return validUserComponent;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+     * component package and user.
+     *
+     * @param component the component whose package should be enabled.
+     * @param userId the user that owns the given component.
+     */
+    private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+        if (mGuard) {
+            // Impossible
+            throw new IllegalStateException("Enabling permissions without disabling.");
+        }
+        mGuard = true;
+
+        PackageManager pm = mContext.getPackageManager();
+
+        String pName = component.getPackageName();
+        if (pm == null) {
+            Slog.e(TAG, "Couldn't set implied permissions for " + pName +
+                ", PackageManager isn't running");
+            return;
+        }
+
+        ApplicationInfo info = null;
+        try {
+            info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA);
+        } catch (NameNotFoundException e) {
+        }
+
+        if (info == null) {
+            Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package.");
+            return;
+        }
+
+        if (!(info.isSystemApp() || info.isUpdatedSystemApp())) {
+            return; // Application is not pre-installed, avoid setting implied permissions
+        }
+
+        mWasDefaultGranted = true;
+
+        grantOverlayAccess(pName, userId);
+        grantNotificationPolicyAccess(pName);
+        grantNotificationListenerAccess(pName, userId);
+    }
+
+    /**
+     * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
+     * component package and user.
+     *
+     * @param component the component whose package should be disabled.
+     * @param userId the user that owns the given component.
+     */
+    private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
+        if (!mGuard) {
+            // Impossible
+            throw new IllegalStateException("Disabling permissions without enabling.");
+        }
+        mGuard = false;
+
+        PackageManager pm = mContext.getPackageManager();
+
+        if (pm == null) {
+            Slog.e(TAG, "Couldn't remove implied permissions for " + component +
+                ", PackageManager isn't running");
+            return;
+        }
+
+        String pName = component.getPackageName();
+        if (mWasDefaultGranted) {
+            revokeOverlayAccess(userId);
+            revokeNotificationPolicyAccess(pName);
+            revokeNotificiationListenerAccess();
+            mWasDefaultGranted = false;
+        }
+
+    }
+
+    private void grantOverlayAccess(String pkg, UserHandle userId) {
+        PackageManager pm = mContext.getPackageManager();
+        boolean prev = (PackageManager.PERMISSION_GRANTED ==
+                pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg));
+        mPreviousManageOverlayPackage = null;
+        if (!prev) {
+            pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW,
+                    userId);
+            mPreviousManageOverlayPackage = pkg;
+        }
+    }
+
+    private void revokeOverlayAccess(UserHandle userId) {
+        PackageManager pm = mContext.getPackageManager();
+        if (mPreviousManageOverlayPackage != null) {
+            pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
+                    android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
+            mPreviousManageOverlayPackage = null;
+        }
+    }
+
+
+    private void grantNotificationPolicyAccess(String pkg) {
+        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+        boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
+        mPreviousNotificationPolicyAccessPackage = null;
+        if (!prev) {
+            mPreviousNotificationPolicyAccessPackage = pkg;
+            nm.setNotificationPolicyAccessGranted(pkg, true);
+        }
+    }
+
+    private void revokeNotificationPolicyAccess(String pkg) {
+        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+        if (mPreviousNotificationPolicyAccessPackage != null) {
+            nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
+            mPreviousNotificationPolicyAccessPackage = null;
+        }
+    }
+
+    private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
+        PackageManager pm = mContext.getPackageManager();
+        ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
+                userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
+                android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
+        ContentResolver resolver = mContext.getContentResolver();
+
+        ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+        mPreviousToggledListenerSettings.clear();
+
+        for (ComponentName c : possibleServices) {
+            String flatName = c.flattenToString();
+            if (Objects.equals(c.getPackageName(), pkg)
+                    && !current.contains(flatName)) {
+                mPreviousToggledListenerSettings.add(flatName);
+                current.add(flatName);
+            }
         }
 
-        if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent))  {
-            mCurrentVrModeComponent = calling;
-            mCurrentVrModeUser = userId;
-            sendUpdatedCaller = true;
+        if (current.size() > 0) {
+            String flatSettings = formatSettings(current);
+            Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                    flatSettings);
         }
-
-        if (mCurrentVrService != null && sendUpdatedCaller) {
-            final ComponentName c = mCurrentVrModeComponent;
-            mCurrentVrService.sendEvent(new PendingEvent() {
-                @Override
-                public void runEvent(IInterface service) throws RemoteException {
-                    IVrListener l = (IVrListener) service;
-                    l.focusedActivityChanged(c);
-                }
-            });
-        }
-
-        return validUserComponent;
     }
 
+    private void revokeNotificiationListenerAccess() {
+        if (mPreviousToggledListenerSettings.isEmpty()) {
+            return;
+        }
+
+        ContentResolver resolver = mContext.getContentResolver();
+        ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+        current.removeAll(mPreviousToggledListenerSettings);
+        mPreviousToggledListenerSettings.clear();
+
+        String flatSettings = formatSettings(current);
+        Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                flatSettings);
+    }
+
+    private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
+        String flat = Settings.Secure.getString(resolver,
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+        ArraySet<String> current = new ArraySet<>();
+        if (flat != null) {
+            String[] allowed = flat.split(":");
+            for (String s : allowed) {
+                current.add(s);
+            }
+        }
+        return current;
+    }
+
+    private static String formatSettings(Collection<String> c) {
+        if (c == null || c.isEmpty()) {
+            return "";
+        }
+
+        StringBuilder b = new StringBuilder();
+        boolean start = true;
+        for (String s : c) {
+            if ("".equals(s)) {
+                continue;
+            }
+            if (!start) {
+                b.append(':');
+            }
+            b.append(s);
+            start = false;
+        }
+        return b.toString();
+    }
+
+
+
     private void createAndConnectService(@NonNull ComponentName component, int userId) {
         mCurrentVrService = VrManagerService.create(mContext, component, userId);
         mCurrentVrService.connect();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 4848523..fb3c6ec 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,8 +16,8 @@
 
 package com.android.server.wallpaper;
 
-import static android.app.WallpaperManager.FLAG_SET_SYSTEM;
-import static android.app.WallpaperManager.FLAG_SET_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.app.WallpaperManager.FLAG_LOCK;
 import static android.os.ParcelFileDescriptor.*;
 
 import android.app.ActivityManager;
@@ -231,7 +231,7 @@
                                         false, wallpaper, null);
                             }
                             if (lockWallpaperChanged
-                                    || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) {
+                                    || (wallpaper.whichPending & FLAG_LOCK) != 0) {
                                 if (DEBUG) {
                                     Slog.i(TAG, "Lock-relevant wallpaper changed");
                                 }
@@ -505,7 +505,7 @@
                                 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
                                     > SystemClock.uptimeMillis()) {
                             Slog.w(TAG, "Reverting to built-in wallpaper!");
-                            clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null);
+                            clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
                         } else {
                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
                         }
@@ -584,7 +584,7 @@
                         if (!bindWallpaperComponentLocked(comp, false, false,
                                 wallpaper, null)) {
                             Slog.w(TAG, "Wallpaper no longer available; reverting to default");
-                            clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+                            clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
                         }
                     }
                 }
@@ -664,7 +664,7 @@
                     if (doit) {
                         Slog.w(TAG, "Wallpaper uninstalled, removing: "
                                 + wallpaper.wallpaperComponent);
-                        clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+                        clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
                     }
                 }
             }
@@ -684,7 +684,7 @@
                 } catch (NameNotFoundException e) {
                     Slog.w(TAG, "Wallpaper component gone, removing: "
                             + wallpaper.wallpaperComponent);
-                    clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
+                    clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
                 }
             }
             if (wallpaper.nextWallpaperComponent != null
@@ -746,7 +746,7 @@
                 if (DEBUG) {
                     Slog.i(TAG, "Unable to regenerate crop; resetting");
                 }
-                clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null);
+                clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
             }
         } else {
             if (DEBUG) {
@@ -842,7 +842,7 @@
     void switchUser(int userId, IRemoteCallback reply) {
         synchronized (mLock) {
             mCurrentUserId = userId;
-            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
             // Not started watching yet, in case wallpaper data was loaded for other reasons.
             if (wallpaper.wallpaperObserver == null) {
                 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -865,7 +865,7 @@
                 e = e1;
             }
             Slog.w(TAG, "Failure starting previous wallpaper", e);
-            clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply);
+            clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
         }
     }
 
@@ -885,12 +885,12 @@
     }
 
     void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
         }
 
         WallpaperData wallpaper = null;
-        if (which == FLAG_SET_LOCK) {
+        if (which == FLAG_LOCK) {
             wallpaper = mLockWallpaperMap.get(userId);
             if (wallpaper == null) {
                 // It's already gone; we're done.
@@ -916,7 +916,7 @@
             if (wallpaper.wallpaperFile.exists()) {
                 wallpaper.wallpaperFile.delete();
                 wallpaper.cropFile.delete();
-                if (which == FLAG_SET_LOCK) {
+                if (which == FLAG_LOCK) {
                     mLockWallpaperMap.remove(userId);
                     final IWallpaperManagerCallback cb = mKeyguardListener;
                     if (cb != null) {
@@ -1008,7 +1008,7 @@
         }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
-            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
             if (width <= 0 || height <= 0) {
                 throw new IllegalArgumentException("width and height must be > 0");
             }
@@ -1070,7 +1070,7 @@
         }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
-            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
+            WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
             if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
                 throw new IllegalArgumentException("padding must be positive: " + padding);
             }
@@ -1103,13 +1103,13 @@
         wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
 
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
         }
 
         synchronized (mLock) {
             final SparseArray<WallpaperData> whichSet =
-                    (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+                    (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
             WallpaperData wallpaper = whichSet.get(wallpaperUserId);
             if (wallpaper == null) {
                 // common case, this is the first lookup post-boot of the system or
@@ -1157,12 +1157,12 @@
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
 
-        if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+        if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
         }
 
         final SparseArray<WallpaperData> map =
-                (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+                (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
         synchronized (mLock) {
             WallpaperData wallpaper = map.get(userId);
             if (wallpaper != null) {
@@ -1186,7 +1186,7 @@
             Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
-        if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) {
+        if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
             Slog.e(TAG, "Must specify a valid wallpaper category to set");
             return null;
         }
@@ -1285,6 +1285,7 @@
                 wallpaper.imageWallpaperPending = false;
                 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
                     wallpaper.wallpaperId = makeWallpaperIdLocked();
+                    notifyCallbacksLocked(wallpaper);
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -1637,7 +1638,7 @@
         // Combined or just-system operations use the 'system' WallpaperData
         // for this use; lock-only operations use the dedicated one.
         final SparseArray<WallpaperData> whichSet =
-                (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+                (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
         WallpaperData wallpaper = whichSet.get(userId);
         if (wallpaper == null) {
             // common case, this is the first lookup post-boot of the system or
@@ -1648,7 +1649,7 @@
             // yet a lock-only wallpaper set for this user, so we need to establish
             // it now.
             if (wallpaper == null) {
-                if (which == FLAG_SET_LOCK) {
+                if (which == FLAG_LOCK) {
                     wallpaper = new WallpaperData(userId,
                             WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
                     mLockWallpaperMap.put(userId, wallpaper);
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
similarity index 64%
rename from services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
rename to services/core/java/com/android/server/webkit/SystemImpl.java
index 4dbd02d..6052a6e 100644
--- a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -19,15 +19,22 @@
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings.Global;
 import android.provider.Settings;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
-import android.webkit.WebViewFactory;
 import android.webkit.WebViewFactory.MissingWebViewPackageException;
+import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
 
 import com.android.internal.util.XmlUtils;
@@ -42,8 +49,8 @@
  * Default implementation for the WebView preparation Utility interface.
  * @hide
  */
-public class WebViewUtilityImpl implements WebViewUtilityInterface {
-    private static final String TAG = WebViewUtilityImpl.class.getSimpleName();
+public class SystemImpl implements SystemInterface {
+    private static final String TAG = SystemImpl.class.getSimpleName();
     private static final String TAG_START = "webviewproviders";
     private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
     private static final String TAG_PACKAGE_NAME = "packageName";
@@ -87,10 +94,10 @@
                             parser.getAttributeValue(null, TAG_AVAILABILITY));
                     boolean isFallback = "true".equals(
                             parser.getAttributeValue(null, TAG_FALLBACK));
-                    WebViewProviderInfo currentProvider =
-                            new WebViewProviderInfo(packageName, description, availableByDefault,
-                                isFallback, readSignatures(parser));
-                    if (currentProvider.isFallbackPackage()) {
+                    WebViewProviderInfo currentProvider = new WebViewProviderInfo(
+                            packageName, description, availableByDefault, isFallback,
+                            readSignatures(parser));
+                    if (currentProvider.isFallback) {
                         numFallbackPackages++;
                         if (numFallbackPackages > 1) {
                             throw new AndroidRuntimeException(
@@ -158,4 +165,67 @@
         } catch (RemoteException e) {
         }
     }
+
+    @Override
+    public boolean isFallbackLogicEnabled() {
+        // Note that this is enabled by default (i.e. if the setting hasn't been set).
+        return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
+                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
+    }
+
+    @Override
+    public void enableFallbackLogic(boolean enable) {
+        Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
+                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
+    }
+
+    @Override
+    public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
+        context.getPackageManager().deletePackage(packageName,
+                new IPackageDeleteObserver.Stub() {
+            public void packageDeleted(String packageName, int returnCode) {
+                // Ignore returnCode since the deletion could fail, e.g. we might be trying
+                // to delete a non-updated system-package (and we should still disable the
+                // package)
+                enablePackageForAllUsers(context, packageName, false);
+            }
+        }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+    }
+
+    @Override
+    public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
+        UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
+        for(UserInfo userInfo : userManager.getUsers()) {
+            enablePackageForUser(packageName, enable, userInfo.id);
+        }
+    }
+
+    @Override
+    public void enablePackageForUser(String packageName, boolean enable, int userId) {
+        try {
+            AppGlobals.getPackageManager().setApplicationEnabledSetting(
+                    packageName,
+                    enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
+                    userId, null);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
+        }
+    }
+
+    @Override
+    public boolean systemIsDebuggable() {
+        return Build.IS_DEBUGGABLE;
+    }
+
+    @Override
+    public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+            throws NameNotFoundException {
+        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+        return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
+    }
+
+    // flags declaring we want extra info from the package manager for webview providers
+    private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
+            | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
similarity index 67%
rename from services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
rename to services/core/java/com/android/server/webkit/SystemInterface.java
index 1919f40..b5eb0a7 100644
--- a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -16,22 +16,35 @@
 
 package com.android.server.webkit;
 
-import android.webkit.WebViewProviderInfo;
 import android.content.Context;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.webkit.WebViewProviderInfo;
 
 /**
- * Utility interface for the WebViewUpdateService.
+ * System interface for the WebViewUpdateService.
  * This interface provides a way to test the WebView preparation mechanism - during normal use this
  * interface is implemented using calls to the Android framework, but by providing an alternative
  * implementation we can test the WebView preparation logic without reaching other framework code.
+ *
  * @hide
  */
-public interface WebViewUtilityInterface {
+public interface SystemInterface {
     public WebViewProviderInfo[] getWebViewPackages();
     public int onWebViewProviderChanged(PackageInfo packageInfo);
 
     public String getUserChosenWebViewProvider(Context context);
     public void updateUserSetting(Context context, String newProviderName);
     public void killPackageDependents(String packageName);
+
+    public boolean isFallbackLogicEnabled();
+    public void enableFallbackLogic(boolean enable);
+
+    public void uninstallAndDisablePackageForAllUsers(Context context, String packageName);
+    public void enablePackageForAllUsers(Context context, String packageName, boolean enable);
+    public void enablePackageForUser(String packageName, boolean enable, int userId);
+
+    public boolean systemIsDebuggable();
+    public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
+            throws NameNotFoundException;
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 50699f8..4669676 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -16,28 +16,20 @@
 
 package com.android.server.webkit;
 
-import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
-import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.PatternMatcher;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings.Global;
-import android.provider.Settings;
-import android.util.AndroidRuntimeException;
+import android.util.Base64;
 import android.util.Slog;
 import android.webkit.IWebViewUpdateService;
 import android.webkit.WebViewFactory;
@@ -49,7 +41,6 @@
 import java.io.FileDescriptor;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -72,15 +63,13 @@
 
     // The WebView package currently in use (or the one we are preparing).
     private PackageInfo mCurrentWebViewPackage = null;
-    // The WebView providers that are currently available.
-    private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
 
     private BroadcastReceiver mWebViewUpdatedReceiver;
-    private WebViewUtilityInterface mWebViewUtility;
+    private SystemInterface mSystemInterface;
 
     public WebViewUpdateService(Context context) {
         super(context);
-        mWebViewUtility = new WebViewUtilityImpl();
+        mSystemInterface = new SystemImpl();
     }
 
     @Override
@@ -102,7 +91,7 @@
                     // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire
                     // package, not just a component
                     if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
-                        if (!WebViewFactory.entirePackageChanged(intent)) {
+                        if (!entirePackageChanged(intent)) {
                             return;
                         }
                     }
@@ -116,7 +105,7 @@
 
                     updateFallbackState(context, intent);
 
-                    for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
+                    for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
                         String webviewPackage = "package:" + provider.packageName;
 
                         if (webviewPackage.equals(intent.getDataString())) {
@@ -126,7 +115,6 @@
                             PackageInfo newPackage = null;
                             synchronized(WebViewUpdateService.this) {
                                 try {
-                                    updateValidWebViewPackages();
                                     newPackage = findPreferredWebViewPackage();
                                     if (mCurrentWebViewPackage != null)
                                         oldProviderName = mCurrentWebViewPackage.packageName;
@@ -155,7 +143,7 @@
                                 // package that was not the previous provider then we must kill
                                 // packages dependent on the old package ourselves. The framework
                                 // only kills dependents of packages that are being removed.
-                                mWebViewUtility.killPackageDependents(oldProviderName);
+                                mSystemInterface.killPackageDependents(oldProviderName);
                             }
                             return;
                         }
@@ -168,7 +156,7 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
         // Make sure we only receive intents for WebView packages from our config file.
-        for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
+        for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
             filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
         }
         getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
@@ -180,42 +168,34 @@
         publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
     }
 
-    private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
+    private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
         for (WebViewProviderInfo provider : providers) {
-            if (provider.isAvailableByDefault() && provider.isEnabled()
-                    && provider.isValidProvider() && !provider.isFallbackPackage()) {
-                return true;
+            if (provider.availableByDefault && !provider.isFallback) {
+                try {
+                    PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
+                    if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
+                        return true;
+                    }
+                } catch (NameNotFoundException e) {
+                    // A non-existent provider is neither valid nor enabled
+                }
             }
         }
         return false;
     }
 
-    private static void enablePackageForUser(String packageName, boolean enable, int userId) {
-        try {
-            AppGlobals.getPackageManager().setApplicationEnabledSetting(
-                    packageName,
-                    enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
-                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
-                    userId, null);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
-        }
-    }
-
     /**
      * Called when a new user has been added to update the state of its fallback package.
      */
     void handleNewUser(int userId) {
-        if (!isFallbackLogicEnabled()) return;
+        if (!mSystemInterface.isFallbackLogicEnabled()) return;
 
-        WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
+        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
         WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
         if (fallbackProvider == null) return;
-        boolean existsValidNonFallbackProvider =
-            existsValidNonFallbackProvider(webviewProviders);
 
-        enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
-                userId);
+        mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
+                !existsValidNonFallbackProvider(webviewProviders), userId);
     }
 
     /**
@@ -224,9 +204,9 @@
      * otherwise, enable the fallback package.
      */
     void updateFallbackState(final Context context, final Intent intent) {
-        if (!isFallbackLogicEnabled()) return;
+        if (!mSystemInterface.isFallbackLogicEnabled()) return;
 
-        WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
+        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
 
         if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
                     || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
@@ -236,7 +216,7 @@
             for (WebViewProviderInfo provider : webviewProviders) {
                 String webviewPackage = "package:" + provider.packageName;
                 if (webviewPackage.equals(intent.getDataString())) {
-                    if (provider.isAvailableByDefault()) {
+                    if (provider.availableByDefault) {
                         changedPackage = provider.packageName;
                     }
                     break;
@@ -251,76 +231,44 @@
         if (fallbackProvider == null) return;
         boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
 
+        boolean isFallbackEnabled = false;
+        try {
+            isFallbackEnabled =
+                isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider));
+        } catch (NameNotFoundException e) {
+        }
+
         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.
-                && (fallbackProvider.isEnabled() || intent == null)) {
-            // Uninstall and disable fallback package for all users.
-            context.getPackageManager().deletePackage(fallbackProvider.packageName,
-                    new IPackageDeleteObserver.Stub() {
-                public void packageDeleted(String packageName, int returnCode) {
-                    // Ignore returnCode since the deletion could fail, e.g. we might be trying
-                    // to delete a non-updated system-package (and we should still disable the
-                    // package)
-                    UserManager userManager =
-                        (UserManager)context.getSystemService(Context.USER_SERVICE);
-                    // Disable the fallback package for all users.
-                    for(UserInfo userInfo : userManager.getUsers()) {
-                        enablePackageForUser(packageName, false, userInfo.id);
-                    }
-                }
-            }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
+                && (isFallbackEnabled || intent == null)) {
+            mSystemInterface.uninstallAndDisablePackageForAllUsers(context,
+                    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.
-                && (!fallbackProvider.isEnabled() || intent==null)) {
+                && (!isFallbackEnabled || intent==null)) {
             // Enable the fallback package for all users.
-            UserManager userManager =
-                (UserManager)context.getSystemService(Context.USER_SERVICE);
-            for(UserInfo userInfo : userManager.getUsers()) {
-                enablePackageForUser(fallbackProvider.packageName, true, userInfo.id);
-            }
+            mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true);
         }
     }
 
-    private static boolean isFallbackLogicEnabled() {
-        // Note that this is enabled by default (i.e. if the setting hasn't been set).
-        return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
-                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
-    }
-
-    private static void enableFallbackLogic(boolean enable) {
-        Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
-                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
-    }
-
     /**
      * Returns the only fallback provider, or null if there is none.
      */
     private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
         for (WebViewProviderInfo provider : webviewPackages) {
-            if (provider.isFallbackPackage()) {
+            if (provider.isFallback) {
                 return provider;
             }
         }
         return null;
     }
 
-    private static boolean containsAvailableNonFallbackProvider(
-            WebViewProviderInfo[] webviewPackages) {
-        for (WebViewProviderInfo provider : webviewPackages) {
-            if (provider.isAvailableByDefault() && provider.isEnabled()
-                    && provider.isValidProvider() && !provider.isFallbackPackage()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private boolean isFallbackPackage(String packageName) {
-        if (packageName == null || !isFallbackLogicEnabled()) return false;
+        if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;
 
-        WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
+        WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
         WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
         return (fallbackProvider != null
                 && packageName.equals(fallbackProvider.packageName));
@@ -336,7 +284,6 @@
         updateFallbackState(getContext(), null);
         try {
             synchronized(this) {
-                updateValidWebViewPackages();
                 mCurrentWebViewPackage = findPreferredWebViewPackage();
                 onWebViewProviderChanged(mCurrentWebViewPackage);
             }
@@ -357,13 +304,13 @@
         PackageInfo newPackage = null;
         synchronized(this) {
             oldPackage = mCurrentWebViewPackage;
-            mWebViewUtility.updateUserSetting(getContext(), newProviderName);
+            mSystemInterface.updateUserSetting(getContext(), newProviderName);
 
             try {
                 newPackage = findPreferredWebViewPackage();
                 if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
                     // If we don't perform the user change, revert the settings change.
-                    mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
+                    mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
                     return newPackage.packageName;
                 }
             } catch (WebViewFactory.MissingWebViewPackageException e) {
@@ -377,7 +324,7 @@
         }
         // Kill apps using the old provider
         if (oldPackage != null) {
-            mWebViewUtility.killPackageDependents(oldPackage.packageName);
+            mSystemInterface.killPackageDependents(oldPackage.packageName);
         }
         return newPackage.packageName;
     }
@@ -391,14 +338,14 @@
             mAnyWebViewInstalled = true;
             if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
                 mCurrentWebViewPackage = newPackage;
-                mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
+                mSystemInterface.updateUserSetting(getContext(), newPackage.packageName);
 
                 // The relro creations might 'finish' (not start at all) before
                 // WebViewFactory.onWebViewProviderChanged which means we might not know the number
                 // of started creations before they finish.
                 mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
                 mNumRelroCreationsFinished = 0;
-                mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
+                mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage);
                 // If the relro creations finish before we know the number of started creations we
                 // will have to do any cleanup/notifying here.
                 checkIfRelrosDoneLocked();
@@ -408,24 +355,42 @@
         }
     }
 
-    /**
-     * Updates the currently valid WebView provider packages.
-     * Should be used when a provider has been installed or removed.
-     * @hide
-     * */
-    private void updateValidWebViewPackages() {
-        List<WebViewProviderInfo> webViewProviders  =
-            new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
-        Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
-        // remove non-valid packages
-        while(it.hasNext()) {
-            WebViewProviderInfo current = it.next();
-            if (!current.isValidProvider())
-                it.remove();
+    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 (isValidProvider(allProviders[n], packageInfo)) {
+                    providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
+                }
+            } catch (NameNotFoundException e) {
+                // Don't add non-existent packages
+            }
         }
-        synchronized(this) {
-            mCurrentValidWebViewPackages =
-                webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+        return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
+    }
+
+    /**
+     * Fetch only the currently valid WebView packages.
+     **/
+    private WebViewProviderInfo[] getValidWebViewPackages() {
+        ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
+        WebViewProviderInfo[] providers = new WebViewProviderInfo[providersAndPackageInfos.length];
+        for(int n = 0; n < providersAndPackageInfos.length; n++) {
+            providers[n] = providersAndPackageInfos[n].provider;
+        }
+        return providers;
+    }
+
+    private class ProviderAndPackageInfo {
+        public final WebViewProviderInfo provider;
+        public final PackageInfo packageInfo;
+
+        public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
+            this.provider = provider;
+            this.packageInfo = packageInfo;
         }
     }
 
@@ -437,28 +402,30 @@
      * @hide
      */
     private PackageInfo findPreferredWebViewPackage() {
-        WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
+        ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
 
-        String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
+        String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext());
 
         // If the user has chosen provider, use that
-        for (WebViewProviderInfo provider : providers) {
-            if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
-                return provider.getPackageInfo();
+        for (ProviderAndPackageInfo providerAndPackage : providers) {
+            if (providerAndPackage.provider.packageName.equals(userChosenProvider)
+                    && isEnabledPackage(providerAndPackage.packageInfo)) {
+                return providerAndPackage.packageInfo;
             }
         }
 
         // User did not choose, or the choice failed; use the most stable provider that is
         // enabled and available by default (not through user choice).
-        for (WebViewProviderInfo provider : providers) {
-            if (provider.isAvailableByDefault() && provider.isEnabled()) {
-                return provider.getPackageInfo();
+        for (ProviderAndPackageInfo providerAndPackage : providers) {
+            if (providerAndPackage.provider.availableByDefault
+                    && isEnabledPackage(providerAndPackage.packageInfo)) {
+                return providerAndPackage.packageInfo;
             }
         }
 
         // Could not find any enabled package either, use the most stable provider.
-        for (WebViewProviderInfo provider : providers) {
-            return provider.getPackageInfo();
+        for (ProviderAndPackageInfo providerAndPackage : providers) {
+            return providerAndPackage.packageInfo;
         }
 
         mAnyWebViewInstalled = false;
@@ -466,6 +433,64 @@
                 "Could not find a loadable WebView package");
     }
 
+
+    /**
+     * Returns whether this provider is valid for use as a WebView provider.
+     */
+    public boolean isValidProvider(WebViewProviderInfo configInfo,
+            PackageInfo packageInfo) {
+        if (providerHasValidSignature(configInfo, packageInfo) &&
+                WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean providerHasValidSignature(WebViewProviderInfo provider,
+            PackageInfo packageInfo) {
+        if (mSystemInterface.systemIsDebuggable()) {
+            return true;
+        }
+        Signature[] packageSignatures;
+        // If no signature is declared, instead check whether the package is included in the
+        // system.
+        if (provider.signatures == null || provider.signatures.length == 0) {
+            return packageInfo.applicationInfo.isSystemApp();
+        }
+        packageSignatures = packageInfo.signatures;
+        if (packageSignatures.length != 1)
+            return false;
+
+        final byte[] packageSignature = packageSignatures[0].toByteArray();
+        // Return whether the package signature matches any of the valid signatures
+        for (String signature : provider.signatures) {
+            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
+            if (Arrays.equals(packageSignature, validSignature))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether the given package is enabled.
+     * This state can be changed by the user from Settings->Apps
+     */
+    public boolean isEnabledPackage(PackageInfo packageInfo) {
+        return packageInfo.applicationInfo.enabled;
+    }
+
+    /**
+     * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
+     * than just one of its components).
+     * @hide
+     */
+    public static boolean entirePackageChanged(Intent intent) {
+        String[] componentList =
+            intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+        return Arrays.asList(componentList).contains(
+                intent.getDataString().substring("package:".length()));
+    }
+
     /**
      * Returns whether WebView is ready and is not going to go through its preparation phase again
      * directly.
@@ -588,19 +613,22 @@
                 throw new SecurityException(msg);
             }
 
-            return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
-        }
-
-        @Override // Binder call
-        public WebViewProviderInfo[] getValidWebViewPackages() {
-            synchronized(WebViewUpdateService.this) {
-                return mCurrentValidWebViewPackages;
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                return WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
             }
         }
 
         @Override // Binder call
+        public WebViewProviderInfo[] getValidWebViewPackages() {
+            return WebViewUpdateService.this.getValidWebViewPackages();
+        }
+
+        @Override // Binder call
         public WebViewProviderInfo[] getAllWebViewPackages() {
-            return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
+            return WebViewUpdateService.this.mSystemInterface.getWebViewPackages();
         }
 
         @Override // Binder call
@@ -630,7 +658,7 @@
                 throw new SecurityException(msg);
             }
 
-            WebViewUpdateService.enableFallbackLogic(enable);
+            WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable);
         }
     }
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
index a9461e8..68448f3 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
@@ -36,12 +36,13 @@
 
         final PrintWriter pw = getOutPrintWriter();
         try {
-            // TODO(gsennton) add command for changing WebView provider
             switch(cmd) {
                 case "enable-redundant-packages":
                     return enableFallbackLogic(false);
                 case "disable-redundant-packages":
                     return enableFallbackLogic(true);
+                case "set-webview-implementation":
+                    return setWebViewImplementation();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -58,6 +59,21 @@
         return 0;
     }
 
+    private int setWebViewImplementation() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        String shellChosenPackage = getNextArg();
+        String newPackage = mInterface.changeProviderAndSetting(shellChosenPackage);
+        if (shellChosenPackage.equals(newPackage)) {
+            pw.println("Success");
+            return 0;
+        } else {
+            pw.println(String.format(
+                        "Failed to switch to %s, the WebView implementation is now provided by %s.",
+                        shellChosenPackage, newPackage));
+            return 1;
+        }
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -72,6 +88,8 @@
         pw.println("  disable-redundant-packages");
         pw.println("    Disallow installing and enabling fallback packages when a more-preferred");
         pw.println("    package is available.");
+        pw.println("  set-webview-implementation PACKAGE");
+        pw.println("    Set the WebView implementation to the specified package.");
         pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index b501398..bae628a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -39,6 +39,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
@@ -1213,6 +1214,8 @@
             window.type = windowState.mAttrs.type;
             window.layer = windowState.mLayer;
             window.token = windowState.mClient.asBinder();
+            window.title = windowState.mAttrs.getTitle();
+            window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
 
             WindowState attachedWindow = windowState.mAttachedWindow;
             if (attachedWindow != null) {
@@ -1285,6 +1288,12 @@
                     && !oldWindow.childTokens.equals(newWindow.childTokens)) {
                 return true;
             }
+            if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+                return true;
+            }
+            if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+                return true;
+            }
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 97d0ae0..3ec02b9 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -183,7 +183,12 @@
 
         for (int i = mState.size() - 1; i >= 0; i--) {
             DimLayer.DimLayerUser user = mState.keyAt(i);
-            if (user.isFullscreen()) {
+            DimLayerState state = mState.valueAt(i);
+            // We have to check that we are acutally 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
+            // and we have to make sure we always animate the layer.
+            if (user.isFullscreen() && state.dimLayer == mSharedFullScreenDimLayer) {
                 fullScreen = i;
                 if (mState.valueAt(i).continueDimming) {
                     fullScreenAndDimming = i;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index cf27b97..aace5e7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -589,7 +589,7 @@
     void overridePointerIconLw(int touchSource) {
         mTouchSource = touchSource;
         if (isFromSource(InputDevice.SOURCE_MOUSE)) {
-            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
+            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRABBING);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 0581a16..24783bc 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,38 +16,33 @@
 
 package com.android.server.wm;
 
-import android.os.Looper;
 import android.os.Process;
 import android.view.Display;
 import android.view.InputChannel;
-import android.view.InputEventReceiver;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
 
-public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer {
+class InputConsumerImpl {
     final WindowManagerService mService;
     final InputChannel mServerChannel, mClientChannel;
     final InputApplicationHandle mApplicationHandle;
     final InputWindowHandle mWindowHandle;
-    final InputEventReceiver mInputEventReceiver;
-    final int mWindowLayer;
 
-    public InputConsumerImpl(WindowManagerService service, Looper looper,
-            InputEventReceiver.Factory inputEventReceiverFactory) {
-        String name = "input consumer";
+    InputConsumerImpl(WindowManagerService service, String name, InputChannel inputChannel) {
         mService = service;
 
         InputChannel[] channels = InputChannel.openInputChannelPair(name);
         mServerChannel = channels[0];
-        mClientChannel = channels[1];
+        if (inputChannel != null) {
+            channels[1].transferTo(inputChannel);
+            channels[1].dispose();
+            mClientChannel = inputChannel;
+        } else {
+            mClientChannel = channels[1];
+        }
         mService.mInputManager.registerInputChannel(mServerChannel, null);
 
-        mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
-                mClientChannel, looper);
-
         mApplicationHandle = new InputApplicationHandle(null);
         mApplicationHandle.name = name;
         mApplicationHandle.dispatchingTimeoutNanos =
@@ -57,8 +52,7 @@
         mWindowHandle.name = name;
         mWindowHandle.inputChannel = mServerChannel;
         mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
-        mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType);
-        mWindowHandle.layer = mWindowLayer;
+        mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType);
         mWindowHandle.layoutParamsFlags = 0;
         mWindowHandle.dispatchingTimeoutNanos =
                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
@@ -81,21 +75,15 @@
         mWindowHandle.frameBottom = dh;
     }
 
-    @Override
-    public void dismiss() {
-        synchronized (mService.mWindowMap) {
-            if (mService.removeInputConsumer()) {
-                mInputEventReceiver.dispose();
-                mService.mInputManager.unregisterInputChannel(mServerChannel);
-                mClientChannel.dispose();
-                mServerChannel.dispose();
-            }
-        }
-    }
-
     private int getLayerLw(int windowType) {
         return mService.mPolicy.windowTypeToLayerLw(windowType)
                 * WindowManagerService.TYPE_LAYER_MULTIPLIER
                 + WindowManagerService.TYPE_LAYER_OFFSET;
     }
+
+    void disposeChannelsLw() {
+        mService.mInputManager.unregisterInputChannel(mServerChannel);
+        mClientChannel.dispose();
+        mServerChannel.dispose();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b702180..eea0e73 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -282,6 +282,8 @@
 
         boolean addInputConsumerHandle = mService.mInputConsumer != null;
 
+        boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
+
         // Add all windows on the default display.
         final int numDisplays = mService.mDisplayContents.size();
         final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
@@ -302,6 +304,14 @@
                     addInputConsumerHandle = false;
                 }
 
+                if (addWallpaperInputConsumerHandle) {
+                    if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
+                        // Add the wallpaper input consumer above the first wallpaper window.
+                        addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+                        addWallpaperInputConsumerHandle = false;
+                    }
+                }
+
                 final int flags = child.mAttrs.flags;
                 final int privateFlags = child.mAttrs.privateFlags;
                 final int type = child.mAttrs.type;
@@ -329,6 +339,11 @@
             }
         }
 
+        if (addWallpaperInputConsumerHandle) {
+            // No wallpaper found, add the wallpaper input consumer at the end.
+            addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
+        }
+
         // Send windows to native code.
         mService.mInputManager.setInputWindows(mInputWindowHandles);
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1f03c04..eea0ca0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -425,7 +425,7 @@
         if (mFullscreen
                 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
                 || displayContent == null
-                || displayContent.getDockedStackLocked() != null) {
+                || displayContent.getDockedStackVisibleForUserLocked() != null) {
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0bf7102..0225c9b 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -128,6 +128,10 @@
     // in which case a second window animation would cause jitter.
     private boolean mFreezeMovementAnimations = false;
 
+    // Temporary storage for the new bounds that should be used after the configuration change.
+    // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
+    private final Rect mBoundsAfterRotation = new Rect();
+
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
@@ -343,28 +347,28 @@
             setBounds(mTmpRect2);
         } else {
             mLastUpdateDisplayInfoRotation = newRotation;
-            updateBoundsAfterRotation();
+            updateBoundsAfterRotation(true);
         }
     }
 
-    void onConfigurationChanged() {
+    boolean onConfigurationChanged() {
         mLastConfigChangedRotation = getDisplayInfo().rotation;
-        updateBoundsAfterRotation();
+        return updateBoundsAfterRotation(false);
     }
 
-    void updateBoundsAfterRotation() {
+    boolean updateBoundsAfterRotation(boolean scheduleResize) {
         if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
             // We wait for the rotation values after configuration change and display info. update
             // to be equal before updating the bounds due to rotation change otherwise things might
             // get out of alignment...
-            return;
+            return false;
         }
 
         final int newRotation = getDisplayInfo().rotation;
 
         if (mRotation == newRotation) {
             // Nothing to do here if the rotation didn't change
-            return;
+            return false;
         }
 
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
@@ -373,11 +377,22 @@
             snapDockedStackAfterRotation(mTmpRect2);
         }
 
-        // Post message to inform activity manager of the bounds change simulating
-        // a one-way call. We do this to prevent a deadlock between window manager
-        // lock and activity manager lock been held.
-        mService.mH.obtainMessage(
-                RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+        if (scheduleResize) {
+            // Post message to inform activity manager of the bounds change simulating
+            // a one-way call. We do this to prevent a deadlock between window manager
+            // lock and activity manager lock been held.
+            mService.mH.obtainMessage(RESIZE_STACK, mStackId,
+                    0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
+        } else {
+            mBoundsAfterRotation.set(mTmpRect2);
+        }
+
+        return true;
+    }
+
+    void getBoundsForNewConfiguration(Rect outBounds) {
+        outBounds.set(mBoundsAfterRotation);
+        mBoundsAfterRotation.setEmpty();
     }
 
     /**
@@ -869,6 +884,10 @@
         }
     }
 
+    boolean isAdjustedForMinimizedDock() {
+        return mMinimizeAmount != 0f;
+    }
+
     private boolean adjustForIME(final WindowState imeWin) {
         final int dockedSide = getDockSide();
         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
@@ -938,9 +957,11 @@
                     (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
         } else if (dockSide == DOCKED_LEFT) {
             mTmpAdjustedBounds.set(mBounds);
+            final int width = mBounds.width();
             mTmpAdjustedBounds.right =
                     (int) (minimizeAmount * mDockedStackMinimizeThickness
                             + (1 - minimizeAmount) * mBounds.right);
+            mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
         } else if (dockSide == DOCKED_RIGHT) {
             mTmpAdjustedBounds.set(mBounds);
             mTmpAdjustedBounds.left =
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index f76f03f..3bfcf00 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -191,18 +191,20 @@
     }
 
     private void adjustSpecialWindows() {
-        int layer = mHighestApplicationLayer + 1;
+        int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
         // For pinned and docked stack window, we want to make them above other windows also when
         // these windows are animating.
         while (!mDockedWindows.isEmpty()) {
             layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
         }
 
-        // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
-        // below the divider but above the app windows. It needs to be below the divider in because
-        // the divider sometimes overlaps the app windows.
-        layer++;
         layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+
+        // If we have a dock divider ensure the Input Method is above it.
+        if (mDockDivider != null && mService.mInputMethodWindow != null) {
+            layer = assignAndIncreaseLayerIfNeeded(mService.mInputMethodWindow, layer);
+        }
+        
         // We know that we will be animating a relaunching window in the near future, which will
         // receive a z-order increase. We want the replaced window to immediately receive the same
         // treatment, e.g. to be above the dock divider.
@@ -218,11 +220,12 @@
     private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
         if (win != null) {
             assignAnimLayer(win, layer);
-            layer++;
+            // Make sure we leave space inbetween normal windows for dims and such.
+            layer += WINDOW_LAYER_MULTIPLIER;
         }
         return layer;
     }
-    
+
     private void assignAnimLayer(WindowState w, int layer) {
         w.mLayer = layer;
         w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1a9e206..fbe2803 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -125,6 +125,7 @@
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IShortcutService;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -407,6 +408,11 @@
     InputConsumerImpl mInputConsumer;
 
     /**
+     * The input consumer added to the window manager before all wallpaper windows.
+     */
+    InputConsumerImpl mWallpaperInputConsumer;
+
+    /**
      * Windows that are being resized.  Used so we can tell the client about
      * the resize after closing the transaction in which we resized the
      * underlying surface.
@@ -510,6 +516,8 @@
 
     private final SparseIntArray mTmpTaskIds = new SparseIntArray();
 
+    private final ArrayList<Integer> mChangedStackList = new ArrayList();
+
     boolean mForceResizableTasks = false;
 
     int getDragLayerLocked() {
@@ -1365,7 +1373,7 @@
         // needs to sit above the dock divider, so it doesn't get cut in half. We make the dock
         // divider be a target for IME, so this relationship can occur naturally.
         if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)
-                || type == TYPE_APPLICATION_STARTING || type == TYPE_DOCK_DIVIDER) {
+                || type == TYPE_APPLICATION_STARTING) {
             if (DEBUG_INPUT_METHOD) {
                 Slog.i(TAG_WM, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
                 if (!w.isVisibleOrAdding()) {
@@ -2602,8 +2610,6 @@
                         == PackageManager.PERMISSION_GRANTED;
 
         long origId = Binder.clearCallingIdentity();
-        final boolean preserveGeometry = (attrs != null) && (attrs.privateFlags &
-                WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY) != 0;
         synchronized(mWindowMap) {
             WindowState win = windowForClientLocked(session, client, false);
             if (win == null) {
@@ -2611,7 +2617,7 @@
             }
 
             WindowStateAnimator winAnimator = win.mWinAnimator;
-            if (!preserveGeometry && viewVisibility != View.GONE) {
+            if (viewVisibility != View.GONE) {
                 win.setRequestedSize(requestedWidth, requestedHeight);
             }
 
@@ -2660,9 +2666,7 @@
             if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
                 winAnimator.mAlpha = attrs.alpha;
             }
-            if (!preserveGeometry) {
-                win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
-            }
+            win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
 
             boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0;
             final boolean isDefaultDisplay = win.isDefaultDisplay();
@@ -3397,7 +3401,8 @@
             }
         }
 
-        if (isStackVisibleLocked(DOCKED_STACK_ID)
+        if ((isStackVisibleLocked(DOCKED_STACK_ID)
+                && !mStackIdToStack.get(DOCKED_STACK_ID).isAdjustedForMinimizedDock())
                 || isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
             // We don't let app affect the system orientation when in freeform or docked mode since
             // they don't occupy the entire display and their request can conflict with other apps.
@@ -3579,7 +3584,7 @@
     }
 
     @Override
-    public void setNewConfiguration(Configuration config) {
+    public int[] setNewConfiguration(Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setNewConfiguration()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3591,16 +3596,30 @@
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
-            onConfigurationChanged();
-            mWindowPlacerLocked.performSurfacePlacement();
+            return onConfigurationChanged();
         }
     }
 
-    private void onConfigurationChanged() {
+    @Override
+    public Rect getBoundsForNewConfiguration(int stackId) {
+        synchronized(mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            final Rect outBounds = new Rect();
+            stack.getBoundsForNewConfiguration(outBounds);
+            return outBounds;
+        }
+    }
+
+    private int[] onConfigurationChanged() {
+        mChangedStackList.clear();
         for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
             final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
-            stack.onConfigurationChanged();
+            if (stack.onConfigurationChanged()) {
+                mChangedStackList.add(stack.mStackId);
+            }
         }
+        return mChangedStackList.isEmpty() ?
+                null : ArrayUtils.convertToIntArray(mChangedStackList);
     }
 
     @Override
@@ -4116,6 +4135,14 @@
             for (int i = 0; i < windowsCount; i++) {
                 WindowState win = wtoken.allAppWindows.get(i);
                 if (win == wtoken.startingWindow) {
+                    // Starting window that's exiting will be removed when the animation
+                    // finishes. Mark all relevant flags for that finishExit will proceed
+                    // all the way to actually remove it.
+                    if (!visible && win.isVisibleNow() && wtoken.mAppAnimator.isAnimating()) {
+                        win.mAnimatingExit = true;
+                        win.mRemoveOnExit = true;
+                        win.mWindowRemovalAllowed = true;
+                    }
                     continue;
                 }
 
@@ -9628,13 +9655,37 @@
         }
     }
 
+    private static final class HideNavInputConsumer extends InputConsumerImpl
+            implements WindowManagerPolicy.InputConsumer {
+        private final InputEventReceiver mInputEventReceiver;
+
+        HideNavInputConsumer(WindowManagerService service, Looper looper,
+                             InputEventReceiver.Factory inputEventReceiverFactory) {
+            super(service, "input consumer", null);
+            mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
+                    mClientChannel, looper);
+        }
+
+        @Override
+        public void dismiss() {
+            if (mService.removeInputConsumer()) {
+                synchronized (mService.mWindowMap) {
+                    mInputEventReceiver.dispose();
+                    disposeChannelsLw();
+                }
+            }
+        }
+    }
+
     @Override
-    public InputConsumerImpl addInputConsumer(Looper looper,
+    public WindowManagerPolicy.InputConsumer addInputConsumer(Looper looper,
             InputEventReceiver.Factory inputEventReceiverFactory) {
         synchronized (mWindowMap) {
-            mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory);
+            HideNavInputConsumer inputConsumerImpl = new HideNavInputConsumer(
+                    this, looper, inputEventReceiverFactory);
+            mInputConsumer = inputConsumerImpl;
             mInputMonitor.updateInputWindowsLw(true);
-            return mInputConsumer;
+            return inputConsumerImpl;
         }
     }
 
@@ -9649,6 +9700,24 @@
         }
     }
 
+    public void createWallpaperInputConsumer(InputChannel inputChannel) {
+        synchronized (mWindowMap) {
+            mWallpaperInputConsumer = new InputConsumerImpl(this, "wallpaper input", inputChannel);
+            mWallpaperInputConsumer.mWindowHandle.hasWallpaper = true;
+            mInputMonitor.updateInputWindowsLw(true);
+        }
+    }
+
+    public void removeWallpaperInputConsumer() {
+        synchronized (mWindowMap) {
+            if (mWallpaperInputConsumer != null) {
+                mWallpaperInputConsumer.disposeChannelsLw();
+                mWallpaperInputConsumer = null;
+                mInputMonitor.updateInputWindowsLw(true);
+            }
+        }
+    }
+
     @Override
     public boolean hasNavigationBar() {
         return mPolicy.hasNavigationBar();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 144b823..ec86a0190 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -642,7 +642,7 @@
         mHaveFrame = true;
 
         final Task task = getTask();
-        final boolean fullscreenTask = !inMultiWindowMode();
+        final boolean fullscreenTask = !isInMultiWindowMode();
         final boolean windowsAreFloating = task != null && task.isFloating();
 
         // If the task has temp inset bounds set, we have to make sure all its windows uses
@@ -670,10 +670,18 @@
                 mContainingFrame.bottom = mContainingFrame.top + frozen.height();
             }
             final WindowState imeWin = mService.mInputMethodWindow;
-            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
-                    && mContainingFrame.bottom > cf.bottom) {
-                // IME is up and obscuring this window. Adjust the window position so it is visible.
-                mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+            // IME is up and obscuring this window. Adjust the window position so it is visible.
+            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) {
+                    if (windowsAreFloating && mContainingFrame.bottom > cf.bottom) {
+                        // In freeform we want to move the top up directly.
+                        // TODO: Investigate why this is cf not pf.
+                        mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
+                    } else if (mContainingFrame.bottom > pf.bottom) {
+                        // But in docked we want to behave like fullscreen
+                        // and behave as if the task were given smaller bounds
+                        // for the purposes of layout.
+                        mContainingFrame.bottom = pf.bottom;
+                    }
             }
 
             if (windowsAreFloating) {
@@ -1878,6 +1886,11 @@
     }
 
     private boolean shouldSaveSurface() {
+        if (mWinAnimator.mSurfaceController == null) {
+            // Don't bother if the surface controller is gone for any reason.
+            return false;
+        }
+
         if ((mAttrs.flags & FLAG_SECURE) != 0) {
             // We don't save secure surfaces since their content shouldn't be shown while the app
             // isn't on screen and content might leak through during the transition animation with
@@ -1951,10 +1964,18 @@
             return;
         }
         mSurfaceSaved = false;
-        setHasSurface(true);
-        mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-            Slog.v(TAG, "Restoring saved surface: " + this);
+        if (mWinAnimator.mSurfaceController != null) {
+            setHasSurface(true);
+            mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+                Slog.v(TAG, "Restoring saved surface: " + this);
+            }
+        } else {
+            // mSurfaceController shouldn't be null if mSurfaceSaved was still true at
+            // this point. Even if we destroyed the saved surface because of rotation
+            // or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
+            Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
         }
     }
 
@@ -2226,7 +2247,7 @@
     }
 
     @Override
-    public boolean inMultiWindowMode() {
+    public boolean isInMultiWindowMode() {
         final Task task = getTask();
         return task != null && !task.isFullscreen();
     }
@@ -2527,7 +2548,7 @@
         final int pw = mContainingFrame.width();
         final int ph = mContainingFrame.height();
         final Task task = getTask();
-        final boolean nonFullscreenTask = inMultiWindowMode();
+        final boolean nonFullscreenTask = isInMultiWindowMode();
         final boolean fitToDisplay = task != null && !task.isFloating() && !layoutInParentFrame();
         float x, y;
         int w,h;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1e103f0..8fd8bc0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -967,13 +967,15 @@
             if (appTransformation != null) {
                 tmpMatrix.postConcat(appTransformation.getMatrix());
             }
+
+            // The translation that applies the position of the window needs to be applied at the
+            // end in case that other translations include scaling. Otherwise the scaling will
+            // affect this translation. But it needs to be set before the screen rotation animation
+            // so the pivot point is at the center of the screen for all windows.
+            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
             if (screenAnimation) {
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
-            // The translation that applies the position of the window needs to be applied at the
-            // end in case that other translations include scaling. Otherwise the scaling will
-            // affect this translation.
-            tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
 
             //TODO (multidisplay): Magnification is supported only for the default display.
             if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 3e5ddbc..eda2f39 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -860,6 +860,10 @@
             mService.mInputConsumer.layout(dw, dh);
         }
 
+        if (mService.mWallpaperInputConsumer != null) {
+            mService.mWallpaperInputConsumer.layout(dw, dh);
+        }
+
         final int N = windows.size();
         int i;
 
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index ec5e8c9..14d50ce 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -36,7 +36,8 @@
 enum {
     TEMPERATURE_CURRENT = 0,
     TEMPERATURE_THROTTLING = 1,
-    TEMPERATURE_SHUTDOWN = 2
+    TEMPERATURE_SHUTDOWN = 2,
+    TEMPERATURE_THROTTLING_BELOW_VR_MIN = 3
 };
 
 static struct {
@@ -127,6 +128,13 @@
                                     values[length++] = list[i].shutdown_threshold;
                                 }
                                 break;
+                            case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
+                                if (list[i].vr_throttling_threshold == UNKNOWN_TEMPERATURE) {
+                                    values[length++] = gUndefinedTemperature;
+                                } else {
+                                    values[length++] = list[i].vr_throttling_threshold;
+                                }
+                                break;
                         }
                     }
                 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3e368f5..6fe5c16 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -136,6 +136,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.ParcelableString;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
@@ -184,12 +185,16 @@
 
     private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
+    private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate";
+
     private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component";
 
     private static final String TAG_STATUS_BAR = "statusbar";
 
     private static final String ATTR_DISABLED = "disabled";
 
+    private static final String ATTR_NAME = "name";
+
     private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML =
             "do-not-ask-credentials-on-boot";
 
@@ -420,6 +425,8 @@
         final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
         final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
 
+        final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
+
         // This is the list of component allowed to start lock task mode.
         List<String> mLockTaskPackages = new ArrayList<>();
 
@@ -483,7 +490,8 @@
             }
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
-                new MonitoringCertNotificationTask().execute(intent);
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+                new MonitoringCertNotificationTask().execute(userId);
             }
             if (Intent.ACTION_USER_ADDED.equals(action)) {
                 disableSecurityLoggingIfNotCompliant();
@@ -1480,6 +1488,12 @@
             return "/data/system/";
         }
 
+        void registerContentObserver(Uri uri, boolean notifyForDescendents,
+                ContentObserver observer, int userHandle) {
+            mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents,
+                    observer, userHandle);
+        }
+
         int settingsSecureGetIntForUser(String name, int def, int userHandle) {
             return Settings.Secure.getIntForUser(mContext.getContentResolver(),
                     name, def, userHandle);
@@ -2215,6 +2229,12 @@
                 out.endTag(null, "active-password");
             }
 
+            for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) {
+                out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+                out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i));
+                out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES);
+            }
+
             for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
                 String component = policy.mLockTaskPackages.get(i);
                 out.startTag(null, TAG_LOCK_TASK_COMPONENTS);
@@ -2381,6 +2401,8 @@
                             parser.getAttributeValue(null, "symbols"));
                     policy.mActivePasswordNonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, "nonletter"));
+                } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) {
+                    policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME));
                 } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
                     policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
                 } else if (TAG_STATUS_BAR.equals(tag)) {
@@ -2536,7 +2558,7 @@
         onStartUser(UserHandle.USER_SYSTEM);
 
         // Register an observer for watching for user setup complete.
-        new SetupContentObserver(mHandler).register(mContext.getContentResolver());
+        new SetupContentObserver(mHandler).register();
         // Initialize the user setup state, to handle the upgrade case.
         updateUserSetupComplete();
 
@@ -2632,17 +2654,17 @@
         }
     }
 
-    private class MonitoringCertNotificationTask extends AsyncTask<Intent, Void, Void> {
+    private class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> {
         @Override
-        protected Void doInBackground(Intent... params) {
-            int userHandle = params[0].getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+        protected Void doInBackground(Integer... params) {
+            int userHandle = params[0];
 
             if (userHandle == UserHandle.USER_ALL) {
                 for (UserInfo userInfo : mUserManager.getUsers()) {
                     manageNotification(userInfo.getUserHandle());
                 }
             } else {
-                manageNotification(new UserHandle(userHandle));
+                manageNotification(UserHandle.of(userHandle));
             }
             return null;
         }
@@ -2652,25 +2674,27 @@
                 return;
             }
 
-            // Call out to KeyChain to check for user-added CAs
-            boolean hasCert = false;
+            // Call out to KeyChain to check for CAs which are waiting for approval.
+            final List<String> pendingCertificates;
             try {
-                KeyChainConnection kcs = KeyChain.bindAsUser(mContext, userHandle);
-                try {
-                    if (!kcs.getService().getUserCaAliases().getList().isEmpty()) {
-                        hasCert = true;
-                    }
-                } catch (RemoteException e) {
-                    Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
-                } finally {
-                    kcs.close();
-                }
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            } catch (RuntimeException | AssertionError e) {
-                Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
+                pendingCertificates = getInstalledCaCertificates(userHandle);
+            } catch (RemoteException | RuntimeException e) {
+                Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
+                return;
             }
-            if (!hasCert) {
+
+            synchronized (DevicePolicyManagerService.this) {
+                final DevicePolicyData policy = getUserData(userHandle.getIdentifier());
+
+                // Remove deleted certificates. Flush xml if necessary.
+                if (policy.mAcceptedCaCertificates.retainAll(pendingCertificates)) {
+                    saveSettingsLocked(userHandle.getIdentifier());
+                }
+                // Trim to approved certificates.
+                pendingCertificates.removeAll(policy.mAcceptedCaCertificates);
+            }
+
+            if (pendingCertificates.isEmpty()) {
                 mInjector.getNotificationManager().cancelAsUser(
                         null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
                 return;
@@ -2701,7 +2725,8 @@
 
             final Context userContext;
             try {
-                userContext = mContext.createPackageContextAsUser("android", 0, userHandle);
+                final String packageName = mContext.getPackageName();
+                userContext = mContext.createPackageContextAsUser(packageName, 0, userHandle);
             } catch (PackageManager.NameNotFoundException e) {
                 Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
                 return;
@@ -2720,6 +2745,29 @@
             mInjector.getNotificationManager().notifyAsUser(
                     null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
         }
+
+        private List<String> getInstalledCaCertificates(UserHandle userHandle)
+                throws RemoteException, RuntimeException {
+            KeyChainConnection conn = null;
+            try {
+                conn = KeyChain.bindAsUser(mContext, userHandle);
+                List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
+                List<String> result = new ArrayList<>(aliases.size());
+                for (int i = 0; i < aliases.size(); i++) {
+                    result.add(aliases.get(i).string);
+                }
+                return result;
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return null;
+            } catch (AssertionError e) {
+                throw new RuntimeException(e);
+            } finally {
+                if (conn != null) {
+                    conn.close();
+                }
+            }
+        }
     }
 
     /**
@@ -4070,6 +4118,29 @@
     }
 
     @Override
+    public boolean approveCaCert(String alias, int userId, boolean approval) {
+        enforceManageUsers();
+        synchronized (this) {
+            Set<String> certs = getUserData(userId).mAcceptedCaCertificates;
+            boolean changed = (approval ? certs.add(alias) : certs.remove(alias));
+            if (!changed) {
+                return false;
+            }
+            saveSettingsLocked(userId);
+        }
+        new MonitoringCertNotificationTask().execute(userId);
+        return true;
+    }
+
+    @Override
+    public boolean isCaCertApproved(String alias, int userId) {
+        enforceManageUsers();
+        synchronized (this) {
+            return getUserData(userId).mAcceptedCaCertificates.contains(alias);
+        }
+    }
+
+    @Override
     public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
         enforceCanManageCaCerts(admin);
 
@@ -5796,8 +5867,7 @@
                 transitionCheckNeeded = false;
             } else {
                 // For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS.
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+                enforceCanManageProfileAndDeviceOwners();
             }
 
             final DevicePolicyData policyData = getUserData(userHandle);
@@ -5990,8 +6060,7 @@
             }
             return;
         }
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+        enforceCanManageProfileAndDeviceOwners();
         if (hasUserSetupCompleted(userHandle) && !isCallerWithSystemUid()) {
             throw new IllegalStateException("Cannot set the profile owner on a user which is "
                     + "already set-up");
@@ -6006,8 +6075,7 @@
         int callingUid = mInjector.binderGetCallingUid();
         boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
         if (!isAdb) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+            enforceCanManageProfileAndDeviceOwners();
         }
 
         final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
@@ -6663,6 +6731,9 @@
         }
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin == null) {
+                return false;
+            }
             if (admin.permittedAccessiblityServices == null) {
                 return true;
             }
@@ -6833,6 +6904,9 @@
         }
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin == null) {
+                return false;
+            }
             if (admin.permittedInputMethods == null) {
                 return true;
             }
@@ -7015,7 +7089,7 @@
     }
 
     @Override
-    public boolean getPackageSuspended(ComponentName who, String packageName) {
+    public boolean isPackageSuspended(ComponentName who, String packageName) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
@@ -7103,19 +7177,30 @@
     }
 
     @Override
-    public Bundle getUserRestrictions(ComponentName who, int userHandle) {
+    public Bundle getUserRestrictions(ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return activeAdmin.userRestrictions;
+        }
+    }
+
+    @Override
+    public Bundle getUserRestrictionsForUser(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         Preconditions.checkNotNull(who, "ComponentName is null");
         enforceFullCrossUsersPermission(userHandle);
+        enforceCanManageProfileAndDeviceOwners();
         synchronized (this) {
             ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(who, userHandle);
             if (activeAdmin == null) {
-                throw new SecurityException("No active admin: " + activeAdmin);
-            }
-            if (activeAdmin.getUid() != mInjector.binderGetCallingUid()) {
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
-                        "Calling uid " + mInjector.binderGetCallingUid() + " neither owns the admin"
-                        + " " + who + " nor has MANAGE_PROFILE_AND_DEVICE_OWNERS permission");
+                return null;
             }
             return activeAdmin.userRestrictions;
         }
@@ -7833,9 +7918,9 @@
             super(handler);
         }
 
-        void register(ContentResolver resolver) {
-            resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
-            resolver.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
+        void register() {
+            mInjector.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
+            mInjector.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -8689,6 +8774,11 @@
                 null);
     }
 
+    private void enforceCanManageProfileAndDeviceOwners() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+    }
+
     @Override
     public boolean isUninstallInQueue(final String packageName) {
         enforceCanManageDeviceAdmin();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7b44f98..659450e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -155,6 +155,8 @@
             "com.android.server.search.SearchManagerService$Lifecycle";
     private static final String THERMAL_OBSERVER_CLASS =
             "com.google.android.clockwork.ThermalObserver";
+    private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
+            "com.google.android.clockwork.bluetooth.WearBluetoothService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -167,7 +169,7 @@
      * visual content.
      */
     private static final int DEFAULT_SYSTEM_THEME =
-            com.android.internal.R.style.Theme_Material_DayNight_DarkActionBar;
+            com.android.internal.R.style.Theme_Material_Light_DarkActionBar;
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
@@ -959,8 +961,7 @@
             if (!disableNonCoreServices) {
                 mSystemServiceManager.startService(DockObserver.class);
 
-                if (context.getPackageManager().hasSystemFeature
-                        (PackageManager.FEATURE_WATCH)) {
+                if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
                     mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
                 }
             }
@@ -1132,7 +1133,9 @@
                 mSystemServiceManager.startService(TvInputManagerService.class);
             }
 
-            mSystemServiceManager.startService(MediaResourceMonitorService.class);
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
+                mSystemServiceManager.startService(MediaResourceMonitorService.class);
+            }
 
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartMediaRouterService");
@@ -1170,6 +1173,10 @@
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
         }
 
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
+        }
+
         // Before things start rolling, be sure we have decided whether
         // we are in safe mode.
         final boolean safeMode = wm.detectSafeMode();
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index e27f69e..a881408 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -57,6 +57,17 @@
 
     public static final int HWADDR_LEN = 16;
     public static final int MAX_OPTION_LEN = 255;
+
+    /**
+     * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
+     * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
+     * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
+     * because in general it is risky to assume that the hardware is able to send/receive packets
+     * larger than 1500 bytes even if the network supports it.
+     */
+    private static final int MIN_MTU = 1280;
+    private static final int MAX_MTU = 1500;
+
     /**
      * IP layer definitions.
      */
@@ -917,7 +928,7 @@
                             break;
                         case DHCP_MTU:
                             expectedLen = 2;
-                            mtu = Short.valueOf(packet.getShort());
+                            mtu = packet.getShort();
                             break;
                         case DHCP_DOMAIN_NAME:
                             expectedLen = optionLen;
@@ -1106,6 +1117,8 @@
         results.serverAddress = mServerIdentifier;
         results.vendorInfo = mVendorInfo;
         results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
+        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+
         return results;
     }
 
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index c25fae3..d10834a 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -605,6 +605,10 @@
                 }
             }
             newLp.setDomains(mDhcpResults.domains);
+
+            if (mDhcpResults.mtu != 0) {
+                newLp.setMtu(mDhcpResults.mtu);
+            }
         }
 
         // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 985917b..4d02928 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -41,12 +41,14 @@
 import android.print.IPrintDocumentAdapter;
 import android.print.IPrintJobStateChangeListener;
 import android.print.IPrintManager;
+import android.printservice.recommendation.IRecommendationsChangeListener;
 import android.print.IPrintServicesChangeListener;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.PrintAttributes;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
 import android.print.PrinterId;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
@@ -265,7 +267,7 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
-                // Only the current group members can get enabled services.
+                // Only the current group members can get print services.
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return null;
                 }
@@ -314,6 +316,25 @@
         }
 
         @Override
+        public List<RecommendationInfo> getPrintServiceRecommendations(int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can get print service recommendations.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return null;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getPrintServiceRecommendations();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
                 int userId) {
             observer = Preconditions.checkNotNull(observer);
@@ -543,7 +564,7 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
-                // Only the current group members can remove a print job listener.
+                // Only the current group members can remove a print services change listener.
                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
                     return;
                 }
@@ -558,6 +579,52 @@
         }
 
         @Override
+        public void addPrintServiceRecommendationsChangeListener(
+                IRecommendationsChangeListener listener, int userId)
+                throws RemoteException {
+            listener = Preconditions.checkNotNull(listener);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can add a print service recommendations listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.addPrintServiceRecommendationsChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void removePrintServiceRecommendationsChangeListener(
+                IRecommendationsChangeListener listener, int userId) {
+            listener = Preconditions.checkNotNull(listener);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can remove a print service recommendations
+                // listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId, false);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.removePrintServiceRecommendationsChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             fd = Preconditions.checkNotNull(fd);
             pw = Preconditions.checkNotNull(pw);
diff --git a/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java b/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java
new file mode 100644
index 0000000..fa1f232
--- /dev/null
+++ b/services/print/java/com/android/server/print/RemotePrintServiceRecommendationService.java
@@ -0,0 +1,235 @@
+/*
+ * 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.print;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.printservice.recommendation.IRecommendationService;
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
+import android.printservice.recommendation.RecommendationInfo;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+import static android.content.pm.PackageManager.GET_META_DATA;
+import static android.content.pm.PackageManager.GET_SERVICES;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+
+/**
+ * Connection to a remote print service recommendation service.
+ */
+class RemotePrintServiceRecommendationService {
+    private static final String LOG_TAG = "RemotePrintServiceRecS";
+
+    /** Lock for this object */
+    private final Object mLock = new Object();
+
+    /** Context used for the connection */
+    private @NonNull final Context mContext;
+
+    /**  The connection to the service (if {@link #mIsBound bound}) */
+    @GuardedBy("mLock")
+    private @NonNull final Connection mConnection;
+
+    /** If the service is currently bound. */
+    @GuardedBy("mLock")
+    private boolean mIsBound;
+
+    /** The service once bound */
+    @GuardedBy("mLock")
+    private IRecommendationService mService;
+
+    /**
+     * Callbacks to be called when there are updates to the print service recommendations.
+     */
+    public interface RemotePrintServiceRecommendationServiceCallbacks {
+        /**
+         * Called when there is an update list of print service recommendations.
+         *
+         * @param recommendations The new recommendations.
+         */
+        void onPrintServiceRecommendationsUpdated(
+                @Nullable List<RecommendationInfo> recommendations);
+    }
+
+    /**
+     * @return The intent that is used to connect to the print service recommendation service.
+     */
+    private Intent getServiceIntent(@NonNull UserHandle userHandle) throws Exception {
+        List<ResolveInfo> installedServices = mContext.getPackageManager()
+                .queryIntentServicesAsUser(new Intent(
+                        android.printservice.recommendation.RecommendationService.SERVICE_INTERFACE),
+                        GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING,
+                        userHandle.getIdentifier());
+
+        if (installedServices.size() != 1) {
+            throw new Exception(installedServices.size() + " instead of exactly one service found");
+        }
+
+        ResolveInfo installedService = installedServices.get(0);
+
+        ComponentName serviceName = new ComponentName(
+                installedService.serviceInfo.packageName,
+                installedService.serviceInfo.name);
+
+        ApplicationInfo appInfo = mContext.getPackageManager()
+                .getApplicationInfo(installedService.serviceInfo.packageName, 0);
+
+        if (appInfo == null) {
+            throw new Exception("Cannot read appInfo for service");
+        }
+
+        if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            throw new Exception("Service is not part of the system");
+        }
+
+        if (!android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE.equals(
+                installedService.serviceInfo.permission)) {
+            throw new Exception("Service " + serviceName.flattenToShortString()
+                    + " does not require permission "
+                    + android.Manifest.permission.BIND_PRINT_RECOMMENDATION_SERVICE);
+        }
+
+        Intent serviceIntent = new Intent();
+        serviceIntent.setComponent(serviceName);
+
+        return serviceIntent;
+    }
+
+    /**
+     * Open a new connection to a {@link IRecommendationService remote print service
+     * recommendation service}.
+     *
+     * @param context    The context establishing the connection
+     * @param userHandle The user the connection is for
+     * @param callbacks  The callbacks to call by the service
+     */
+    RemotePrintServiceRecommendationService(@NonNull Context context,
+            @NonNull UserHandle userHandle,
+            @NonNull RemotePrintServiceRecommendationServiceCallbacks callbacks) {
+        mContext = context;
+        mConnection = new Connection(callbacks);
+
+        try {
+            Intent serviceIntent = getServiceIntent(userHandle);
+
+            synchronized (mLock) {
+                mIsBound = mContext.bindServiceAsUser(serviceIntent, mConnection,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, userHandle);
+
+                if (!mIsBound) {
+                    throw new Exception("Failed to bind to service " + serviceIntent);
+                }
+            }
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Could not connect to print service recommendation service", e);
+        }
+    }
+
+    /**
+     * Terminate the connection to the {@link IRecommendationService remote print
+     * service recommendation service}.
+     */
+    void close() {
+        synchronized (mLock) {
+            if (mService != null) {
+                try {
+                    mService.registerCallbacks(null);
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Could not unregister callbacks", e);
+                }
+
+                mService = null;
+            }
+
+            if (mIsBound) {
+                mContext.unbindService(mConnection);
+                mIsBound = false;
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        if (mIsBound || mService != null) {
+            Log.w(LOG_TAG, "Service still connected on finalize()");
+            close();
+        }
+
+        super.finalize();
+    }
+
+    /**
+     * Connection to the service.
+     */
+    private class Connection implements ServiceConnection {
+        private final RemotePrintServiceRecommendationServiceCallbacks mCallbacks;
+
+        public Connection(@NonNull RemotePrintServiceRecommendationServiceCallbacks callbacks) {
+            mCallbacks = callbacks;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                mService = (IRecommendationService)IRecommendationService.Stub.asInterface(service);
+
+                try {
+                    mService.registerCallbacks(new IRecommendationServiceCallbacks.Stub() {
+                        @Override
+                        public void onRecommendationsUpdated(
+                                List<RecommendationInfo> recommendations) {
+                            synchronized (mLock) {
+                                if (mIsBound && mService != null) {
+                                    if (recommendations != null) {
+                                        Preconditions.checkCollectionElementsNotNull(
+                                                recommendations, "recommendation");
+                                    }
+
+                                    mCallbacks.onPrintServiceRecommendationsUpdated(
+                                            recommendations);
+                                }
+                            }
+                        }
+                    });
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Could not register callbacks", e);
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.w(LOG_TAG, "Unexpected termination of connection");
+
+            synchronized (mLock) {
+                mService = null;
+            }
+        }
+    }
+}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 263dead..026942e 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -37,6 +37,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
+import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteCallbackList;
@@ -44,12 +45,14 @@
 import android.os.UserHandle;
 import android.print.IPrintDocumentAdapter;
 import android.print.IPrintJobStateChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
 import android.print.IPrintServicesChangeListener;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.PrintAttributes;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
+import android.printservice.recommendation.RecommendationInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
@@ -68,6 +71,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
 import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
+import com.android.server.print.RemotePrintServiceRecommendationService.RemotePrintServiceRecommendationServiceCallbacks;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -82,7 +86,8 @@
 /**
  * Represents the print state for a user.
  */
-final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
+        RemotePrintServiceRecommendationServiceCallbacks {
 
     private static final String LOG_TAG = "UserState";
 
@@ -122,10 +127,22 @@
 
     private List<PrintJobStateChangeListenerRecord> mPrintJobStateChangeListenerRecords;
 
-    private List<PrintServicesChangeListenerRecord> mPrintServicesChangeListenerRecords;
+    private List<ListenerRecord<IPrintServicesChangeListener>> mPrintServicesChangeListenerRecords;
+
+    private List<ListenerRecord<IRecommendationsChangeListener>>
+            mPrintServiceRecommendationsChangeListenerRecords;
 
     private boolean mDestroyed;
 
+    /** Currently known list of print service recommendations */
+    private List<RecommendationInfo> mPrintServiceRecommendations;
+
+    /**
+     * Connection to the service updating the {@link #mPrintServiceRecommendations print service
+     * recommendations}.
+     */
+    private RemotePrintServiceRecommendationService mPrintServiceRecommendationsService;
+
     public UserState(Context context, int userId, Object lock, boolean lowPriority) {
         mContext = context;
         mUserId = userId;
@@ -409,6 +426,13 @@
         }
     }
 
+    /**
+     * @return The currently known print service recommendations
+     */
+    public @Nullable List<RecommendationInfo> getPrintServiceRecommendations() {
+        return mPrintServiceRecommendations;
+    }
+
     public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -566,7 +590,7 @@
                 mPrintServicesChangeListenerRecords = new ArrayList<>();
             }
             mPrintServicesChangeListenerRecords.add(
-                    new PrintServicesChangeListenerRecord(listener) {
+                    new ListenerRecord<IPrintServicesChangeListener>(listener) {
                         @Override
                         public void onBinderDied() {
                             mPrintServicesChangeListenerRecords.remove(this);
@@ -583,7 +607,7 @@
             }
             final int recordCount = mPrintServicesChangeListenerRecords.size();
             for (int i = 0; i < recordCount; i++) {
-                PrintServicesChangeListenerRecord record =
+                ListenerRecord<IPrintServicesChangeListener> record =
                         mPrintServicesChangeListenerRecords.get(i);
                 if (record.listener.asBinder().equals(listener.asBinder())) {
                     mPrintServicesChangeListenerRecords.remove(i);
@@ -596,6 +620,54 @@
         }
     }
 
+    public void addPrintServiceRecommendationsChangeListener(
+            @NonNull IRecommendationsChangeListener listener) throws RemoteException {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+                mPrintServiceRecommendationsChangeListenerRecords = new ArrayList<>();
+
+                mPrintServiceRecommendationsService =
+                        new RemotePrintServiceRecommendationService(mContext,
+                                UserHandle.getUserHandleForUid(mUserId), this);
+            }
+            mPrintServiceRecommendationsChangeListenerRecords.add(
+                    new ListenerRecord<IRecommendationsChangeListener>(listener) {
+                        @Override
+                        public void onBinderDied() {
+                            mPrintServiceRecommendationsChangeListenerRecords.remove(this);
+                        }
+                    });
+        }
+    }
+
+    public void removePrintServiceRecommendationsChangeListener(
+            @NonNull IRecommendationsChangeListener listener) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+                return;
+            }
+            final int recordCount = mPrintServiceRecommendationsChangeListenerRecords.size();
+            for (int i = 0; i < recordCount; i++) {
+                ListenerRecord<IRecommendationsChangeListener> record =
+                        mPrintServiceRecommendationsChangeListenerRecords.get(i);
+                if (record.listener.asBinder().equals(listener.asBinder())) {
+                    mPrintServiceRecommendationsChangeListenerRecords.remove(i);
+                    break;
+                }
+            }
+            if (mPrintServiceRecommendationsChangeListenerRecords.isEmpty()) {
+                mPrintServiceRecommendationsChangeListenerRecords = null;
+
+                mPrintServiceRecommendations = null;
+
+                mPrintServiceRecommendationsService.close();
+                mPrintServiceRecommendationsService = null;
+            }
+        }
+    }
+
     @Override
     public void onPrintJobStateChanged(PrintJobInfo printJob) {
         mPrintJobForAppCache.onPrintJobStateChanged(printJob);
@@ -608,6 +680,12 @@
     }
 
     @Override
+    public void onPrintServiceRecommendationsUpdated(List<RecommendationInfo> recommendations) {
+        mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED,
+                0, 0, recommendations).sendToTarget();
+    }
+
+    @Override
     public void onPrintersAdded(List<PrinterInfo> printers) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -1058,7 +1136,7 @@
     }
 
     private void handleDispatchPrintServicesChanged() {
-        final List<PrintServicesChangeListenerRecord> records;
+        final List<ListenerRecord<IPrintServicesChangeListener>> records;
         synchronized (mLock) {
             if (mPrintServicesChangeListenerRecords == null) {
                 return;
@@ -1067,7 +1145,7 @@
         }
         final int recordCount = records.size();
         for (int i = 0; i < recordCount; i++) {
-            PrintServicesChangeListenerRecord record = records.get(i);
+            ListenerRecord<IPrintServicesChangeListener> record = records.get(i);
 
             try {
                 record.listener.onPrintServicesChanged();;
@@ -1077,9 +1155,33 @@
         }
     }
 
+    private void handleDispatchPrintServiceRecommendationsUpdated(
+            @Nullable List<RecommendationInfo> recommendations) {
+        final List<ListenerRecord<IRecommendationsChangeListener>> records;
+        synchronized (mLock) {
+            if (mPrintServiceRecommendationsChangeListenerRecords == null) {
+                return;
+            }
+            records = new ArrayList<>(mPrintServiceRecommendationsChangeListenerRecords);
+
+            mPrintServiceRecommendations = recommendations;
+        }
+        final int recordCount = records.size();
+        for (int i = 0; i < recordCount; i++) {
+            ListenerRecord<IRecommendationsChangeListener> record = records.get(i);
+
+            try {
+                record.listener.onRecommendationsChanged();
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error notifying for print service recommendations change", re);
+            }
+        }
+    }
+
     private final class UserStateHandler extends Handler {
         public static final int MSG_DISPATCH_PRINT_JOB_STATE_CHANGED = 1;
         public static final int MSG_DISPATCH_PRINT_SERVICES_CHANGED = 2;
+        public static final int MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED = 3;
 
         public UserStateHandler(Looper looper) {
             super(looper, null, false);
@@ -1096,6 +1198,10 @@
                 case MSG_DISPATCH_PRINT_SERVICES_CHANGED:
                     handleDispatchPrintServicesChanged();
                     break;
+                case MSG_DISPATCH_PRINT_SERVICES_RECOMMENDATIONS_UPDATED:
+                    handleDispatchPrintServiceRecommendationsUpdated(
+                            (List<RecommendationInfo>) message.obj);
+                    break;
                 default:
                     // not reached
             }
@@ -1122,10 +1228,10 @@
         public abstract void onBinderDied();
     }
 
-    private abstract class PrintServicesChangeListenerRecord implements DeathRecipient {
-        @NonNull final IPrintServicesChangeListener listener;
+    private abstract class ListenerRecord<T extends IInterface> implements DeathRecipient {
+        @NonNull final T listener;
 
-        public PrintServicesChangeListenerRecord(@NonNull IPrintServicesChangeListener listener) throws RemoteException {
+        public ListenerRecord(@NonNull T listener) throws RemoteException {
             this.listener = listener;
             listener.asBinder().linkToDeath(this, 0);
         }
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index 876d95b..f8eaf7d 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -261,7 +261,7 @@
 
     private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
             String domains, String serverAddress, String vendorInfo, int leaseDuration,
-            boolean hasMeteredHint, DhcpResults dhcpResults) throws Exception {
+            boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
         assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
         assertEquals(v4Address(gateway), dhcpResults.gateway);
 
@@ -277,6 +277,7 @@
         assertEquals(vendorInfo, dhcpResults.vendorInfo);
         assertEquals(leaseDuration, dhcpResults.leaseDuration);
         assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
+        assertEquals(mtu, dhcpResults.mtu);
     }
 
     @SmallTest
@@ -310,7 +311,7 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
-                null, "192.168.144.3", null, 7200, false, dhcpResults);
+                null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -342,10 +343,70 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
-                null, "192.168.43.1", "ANDROID_METERED", 3600, true, dhcpResults);
+                null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
         assertTrue(dhcpResults.hasMeteredHint());
     }
 
+    private byte[] mtuBytes(int mtu) {
+        // 0x1a02: option 26, length 2. 0xff: no more options.
+        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
+            throw new IllegalArgumentException(
+                String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
+        }
+        String hexString = String.format("1a02%04xff", mtu);
+        return HexEncoding.decode(hexString.toCharArray(), false);
+    }
+
+    private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
+        if (mtuBytes != null) {
+            packet.position(packet.capacity() - mtuBytes.length);
+            packet.put(mtuBytes);
+            packet.clear();
+        }
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
+        DhcpResults dhcpResults = offerPacket.toDhcpResults();
+        assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
+                null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
+    }
+
+    @SmallTest
+    public void testMtu() throws Exception {
+        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+            // IP header.
+            "451001480000000080118849c0a89003c0a89ff7" +
+            // UDP header.
+            "004300440134dcfa" +
+            // BOOTP header.
+            "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options
+            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
+            "3a0400000e103b040000189cff00000000"
+        ).toCharArray(), false));
+
+        checkMtu(packet, 0, null);
+        checkMtu(packet, 0, mtuBytes(1501));
+        checkMtu(packet, 1500, mtuBytes(1500));
+        checkMtu(packet, 1499, mtuBytes(1499));
+        checkMtu(packet, 1280, mtuBytes(1280));
+        checkMtu(packet, 0, mtuBytes(1279));
+        checkMtu(packet, 0, mtuBytes(576));
+        checkMtu(packet, 0, mtuBytes(68));
+        checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
+        checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
+        checkMtu(packet, 0, mtuBytes(-1));
+    }
+
     @SmallTest
     public void testBadHwaddrLength() throws Exception {
         final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
@@ -453,7 +514,7 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
-                null, "1.1.1.1", null, 43200, false, dhcpResults);
+                null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -484,7 +545,7 @@
         assertTrue(offerPacket instanceof DhcpOfferPacket);
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
-                "domain123.co.uk", "192.0.2.254", null, 49094, false, dhcpResults);
+                "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -518,7 +579,7 @@
         assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
-                "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
+                "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -554,7 +615,7 @@
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("10.15.122.242/16", "10.15.200.23",
                 "209.129.128.3,209.129.148.3,209.129.128.6",
-                "wvm.edu", "10.1.105.252", null, 86400, false, dhcpResults);
+                "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
     }
 
     @SmallTest
@@ -621,7 +682,7 @@
         assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
         DhcpResults dhcpResults = offerPacket.toDhcpResults();
         assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
-                null, "192.171.189.2", null, 28800, false, dhcpResults);
+                null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
     }
 
     @SmallTest
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 35777ce..744443f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -15,14 +15,14 @@
  */
 package com.android.server.devicepolicy;
 
-import com.android.internal.widget.LockPatternUtils;
-
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.backup.IBackupManager;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
 import android.media.IAudioService;
+import android.net.Uri;
 import android.os.Looper;
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
@@ -30,12 +30,15 @@
 import android.os.UserManagerInternal;
 import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
 import android.view.IWindowManager;
 
-import java.io.File;
+import com.android.internal.widget.LockPatternUtils;
 
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
+import java.io.File;
+import java.util.Map;
 
 /**
  * Overrides {@link #DevicePolicyManagerService} for dependency injection.
@@ -77,6 +80,7 @@
     }
 
     public final DpmMockContext context;
+    private final MockInjector mMockInjector;
 
     public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
         this(new MockInjector(context, dataDir));
@@ -84,15 +88,36 @@
 
     private DevicePolicyManagerServiceTestable(MockInjector injector) {
         super(injector);
+        mMockInjector = injector;
         this.context = injector.context;
     }
 
+
+    public void notifyChangeToContentObserver(Uri uri, int userHandle) {
+        ContentObserver co = mMockInjector.mContentObservers
+                .get(new Pair<Uri, Integer>(uri, userHandle));
+        if (co != null) {
+            co.onChange(false, uri, userHandle); // notify synchronously
+        }
+
+        // Notify USER_ALL observer too.
+        co = mMockInjector.mContentObservers
+                .get(new Pair<Uri, Integer>(uri, UserHandle.USER_ALL));
+        if (co != null) {
+            co.onChange(false, uri, userHandle); // notify synchronously
+        }
+    }
+
+
     private static class MockInjector extends Injector {
 
         public final DpmMockContext context;
 
         public final File dataDir;
 
+        // Key is a pair of uri and userId
+        private final Map<Pair<Uri, Integer>, ContentObserver> mContentObservers = new ArrayMap<>();
+
         private MockInjector(DpmMockContext context, File dataDir) {
             super(context);
             this.context = context;
@@ -265,6 +290,12 @@
         }
 
         @Override
+        void registerContentObserver(Uri uri, boolean notifyForDescendents,
+                ContentObserver observer, int userHandle) {
+            mContentObservers.put(new Pair<Uri, Integer>(uri, userHandle), observer);
+        }
+
+        @Override
         int settingsSecureGetIntForUser(String name, int def, int userHandle) {
             return context.settings.settingsSecureGetIntForUser(name, def, userHandle);
         }
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 e6963d5..3a2e946 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -543,10 +543,31 @@
     }
 
     /**
-     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
-     * successfully.
+     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
      */
     public void testSetDeviceOwner() throws Exception {
+        setDeviceOwner();
+
+        // Try to set a profile owner on the same user, which should fail.
+        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
+        try {
+            dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
+            fail("IllegalStateException not thrown");
+        } catch (IllegalStateException expected) {
+            assertTrue("Message was: " + expected.getMessage(),
+                    expected.getMessage().contains("already has a device owner"));
+        }
+
+        // DO admin can't be deactivated.
+        dpm.removeActiveAdmin(admin1);
+        assertTrue(dpm.isAdminActive(admin1));
+
+        // TODO Test getDeviceOwnerName() too. To do so, we need to change
+        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+    }
+
+    private void setDeviceOwner() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_USERS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -594,24 +615,6 @@
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
         assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
-
-        // Try to set a profile owner on the same user, which should fail.
-        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
-        dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
-        try {
-            dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
-            fail("IllegalStateException not thrown");
-        } catch (IllegalStateException expected) {
-            assertTrue("Message was: " + expected.getMessage(),
-                    expected.getMessage().contains("already has a device owner"));
-        }
-
-        // DO admin can't be deactivated.
-        dpm.removeActiveAdmin(admin1);
-        assertTrue(dpm.isAdminActive(admin1));
-
-        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
-        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
     }
 
     private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
@@ -1934,5 +1937,211 @@
         // TODO Verify calls to settingsGlobalPutInt.  Tried but somehow mockito threw
         // UnfinishedVerificationException.
     }
-}
 
+    public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception {
+        when(mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+                .thenReturn(false);
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(false);
+        initializeDpms();
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+    }
+
+    public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(false);
+        initializeDpms();
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+
+        // Test again when split user is on
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false);
+    }
+
+    public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false /* because of non-split user */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false /* because of non-split user */);
+    }
+
+    public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(false);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(true);
+        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                false/* because of completed device setup */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                false/* because of non-split user */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because of non-split user */);
+    }
+
+    public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(false);
+        setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                false /* because canAddMoreManagedProfiles returns false */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because calling uid is system user */);
+
+    }
+
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(false);
+        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                false /* because canAddMoreManagedProfiles returns false */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because calling uid is system user */);
+    }
+
+    public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+                true)).thenReturn(true);
+        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
+
+    }
+
+    public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
+            throws Exception {
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+                true)).thenReturn(true);
+        setUserSetupCompleteForUser(true, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE,
+                true/* it's undefined behavior. Can be changed into false in the future */);
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER,
+                false/* because user setup completed */);
+    }
+
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
+            throws Exception {
+        setDeviceOwner();
+
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+                .thenReturn(false);
+        setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
+                false /* can't provision managed profile on system user */);
+    }
+
+    public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
+            throws Exception {
+        setDeviceOwner();
+
+        when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+                .thenReturn(true);
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+                true)).thenReturn(true);
+        setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
+    }
+
+    private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
+        when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
+                userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
+        dpms.notifyChangeToContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), userhandle);
+    }
+
+    private void assertProvisioningAllowed(String action, boolean expected) {
+        assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
+                dpm.isProvisioningAllowed(action));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 8e2ef70..60d7382 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -53,6 +53,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -172,36 +173,36 @@
     }
 
     public static class SettingsForMock {
-        int settingsSecureGetIntForUser(String name, int def, int userHandle) {
+        public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
             return 0;
         }
 
-        void settingsSecurePutIntForUser(String name, int value, int userHandle) {
+        public void settingsSecurePutIntForUser(String name, int value, int userHandle) {
         }
 
-        void settingsSecurePutStringForUser(String name, String value, int userHandle) {
+        public void settingsSecurePutStringForUser(String name, String value, int userHandle) {
         }
 
-        void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
+        public void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
         }
 
-        void settingsSecurePutInt(String name, int value) {
+        public void settingsSecurePutInt(String name, int value) {
         }
 
-        void settingsGlobalPutInt(String name, int value) {
+        public void settingsGlobalPutInt(String name, int value) {
         }
 
-        void settingsSecurePutString(String name, String value) {
+        public void settingsSecurePutString(String name, String value) {
         }
 
-        void settingsGlobalPutString(String name, String value) {
+        public void settingsGlobalPutString(String name, String value) {
         }
 
-        int settingsGlobalGetInt(String name, int def) {
+        public int settingsGlobalGetInt(String name, int value) {
             return 0;
         }
 
-        void securityLogSetLoggingEnabledProperty(boolean enabled) {
+        public void securityLogSetLoggingEnabledProperty(boolean enabled) {
         }
 
         public boolean securityLogGetLoggingEnabledProperty() {
@@ -321,6 +322,8 @@
 
         mUserInfos.add(uh);
         when(userManager.getUsers()).thenReturn(mUserInfos);
+        when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
+        when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
         when(userManager.getUserInfo(anyInt())).thenAnswer(
                 new Answer<UserInfo>() {
                     @Override
diff --git a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
new file mode 100644
index 0000000..83a59fd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -0,0 +1,541 @@
+/*
+ * 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.notification;
+
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class BuzzBeepBlinkTest extends AndroidTestCase {
+
+    @Mock AudioManager mAudioManager;
+    @Mock Vibrator mVibrator;
+    @Mock android.media.IRingtonePlayer mRingtonePlayer;
+    @Mock Handler mHandler;
+
+    private NotificationManagerService mService;
+    private String mPkg = "com.android.server.notification";
+    private int mId = 1001;
+    private int mOtherId = 1002;
+    private String mTag = null;
+    private int mUid = 1000;
+    private int mPid = 2000;
+    private int mScore = 10;
+    private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+    @Override
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
+        when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+
+        mService = new NotificationManagerService(getContext());
+        mService.setAudioManager(mAudioManager);
+        mService.setVibrator(mVibrator);
+        mService.setSystemReady(true);
+        mService.setHandler(mHandler);
+    }
+
+    //
+    // Convenience functions for creating notification records
+    //
+
+    private NotificationRecord getNoisyOtherNotification() {
+        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+                true /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getBeepyNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                true /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getBeepyOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                true /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getQuietNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                false /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getQuietOtherNotification() {
+        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
+                false /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getQuietOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getInsistentBeepyNotification() {
+        return getNotificationRecord(mId, true /* insistent */, false /* once */,
+                true /* noisy */, false /* buzzy*/);
+    }
+
+    private NotificationRecord getBuzzyNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                false /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getBuzzyOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getInsistentBuzzyNotification() {
+        return getNotificationRecord(mId, true /* insistent */, false /* once */,
+                false /* noisy */, true /* buzzy*/);
+    }
+
+    private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
+            boolean noisy, boolean buzzy) {
+        final Builder builder = new Builder(getContext())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setOnlyAlertOnce(once);
+
+        int defaults = 0;
+        if (noisy) {
+            defaults |= Notification.DEFAULT_SOUND;
+        }
+        if (buzzy) {
+            defaults |= Notification.DEFAULT_VIBRATE;
+        }
+        builder.setDefaults(defaults);
+
+        Notification n = builder.build();
+        if (insistent) {
+            n.flags |= Notification.FLAG_INSISTENT;
+        }
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
+                mScore, n, mUser, System.currentTimeMillis());
+        return new NotificationRecord(getContext(), sbn);
+    }
+
+    //
+    // Convenience functions for interacting with mocks
+    //
+
+    private void verifyNeverBeep() throws RemoteException {
+        verify(mRingtonePlayer, never()).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+                anyBoolean(), (AudioAttributes) anyObject());
+    }
+
+    private void verifyBeep() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+                eq(true), (AudioAttributes) anyObject());
+    }
+
+    private void verifyBeepLooped() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).playAsync((Uri) anyObject(), (UserHandle) anyObject(),
+                eq(false), (AudioAttributes) anyObject());
+    }
+
+    private void verifyNeverStopAudio() throws RemoteException {
+        verify(mRingtonePlayer, never()).stopAsync();
+    }
+
+    private void verifyStopAudio() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).stopAsync();
+    }
+
+    private void verifyNeverVibrate() {
+        verify(mVibrator, never()).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+                anyInt(), (AudioAttributes) anyObject());
+    }
+
+    private void verifyVibrate() {
+        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+                eq(-1), (AudioAttributes) anyObject());
+    }
+
+    private void verifyVibrateLooped() {
+        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), (long[]) anyObject(),
+                eq(0), (AudioAttributes) anyObject());
+    }
+
+    private void verifyStopVibrate() {
+        verify(mVibrator, times(1)).cancel();
+    }
+
+    private void verifyNeverStopVibrate() throws RemoteException {
+        verify(mVibrator, never()).cancel();
+    }
+
+    @SmallTest
+    public void testBeep() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeepLooped();
+        verifyNeverVibrate();
+    }
+
+    //
+    // Tests
+    //
+
+    @SmallTest
+    public void testBeepInsistently() throws Exception {
+        NotificationRecord r = getInsistentBeepyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeep();
+    }
+
+    @SmallTest
+    public void testNoInterruptionForMin() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyNeverVibrate();
+    }
+
+    @SmallTest
+    public void testNoInterruptionForIntercepted() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        r.setIntercepted(true);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyNeverVibrate();
+    }
+
+    @SmallTest
+    public void testBeepTwice() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should beep
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+        verifyBeepLooped();
+    }
+
+    @SmallTest
+    public void testHonorAlertOnlyOnceForBeep() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getBeepyOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // update should not beep
+        mService.buzzBeepBlinkLocked(s);
+        verifyNeverBeep();
+    }
+
+    @SmallTest
+    public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getBeepyOnceNotification();
+        s.isUpdate = true;
+
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(s);
+
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+        NotificationRecord other = getNoisyOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(other); // this takes the audio stream
+        Mockito.reset(mRingtonePlayer);
+
+        // should not stop noise, since we no longer own it
+        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietInterloperDoesNotCancelAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord other = getQuietOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // should not stop noise, since it does not own it
+        mService.buzzBeepBlinkLocked(other);
+        verifyNeverStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietUpdateCancelsAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // quiet update should stop making noise
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopAudio();
+    }
+
+    @SmallTest
+    public void testQuietOnceUpdateCancelsAudio() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mRingtonePlayer);
+
+        // stop making noise - this is a weird corner case, but quiet should override once
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopAudio();
+    }
+
+    @SmallTest
+    public void testDemoteSoundToVibrate() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        // the phone is quiet
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyVibrate();
+    }
+
+    @SmallTest
+    public void testDemotInsistenteSoundToVibrate() throws Exception {
+        NotificationRecord r = getInsistentBeepyNotification();
+
+        // the phone is quiet
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyVibrateLooped();
+    }
+
+    @SmallTest
+    public void testVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyVibrate();
+    }
+
+    @SmallTest
+    public void testInsistenteVibrate() throws Exception {
+        NotificationRecord r = getInsistentBuzzyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+        verifyVibrateLooped();
+    }
+
+    @SmallTest
+    public void testVibratTwice() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // update should vibrate
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+        verifyVibrate();
+    }
+
+    @SmallTest
+    public void testHonorAlertOnlyOnceForBuzz() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getBuzzyOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // update should not beep
+        mService.buzzBeepBlinkLocked(s);
+        verifyNeverVibrate();
+    }
+
+    @SmallTest
+    public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+        r.isUpdate = true;
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getBuzzyOnceNotification();
+        s.isUpdate = true;
+
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(s);
+
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+        NotificationRecord other = getNoisyOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
+        Mockito.reset(mVibrator);
+
+        // should not stop vibrate, since we no longer own it
+        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord other = getQuietOtherNotification();
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // should not stop noise, since it does not own it
+        mService.buzzBeepBlinkLocked(other);
+        verifyNeverStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietUpdateCancelsVibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getQuietNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+
+        // quiet update should stop making noise
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietOnceUpdateCancelsvibrate() throws Exception {
+        NotificationRecord r = getBuzzyNotification();
+        NotificationRecord s = getQuietOnceNotification();
+        s.isUpdate = true;
+
+        // set up internal state
+        mService.buzzBeepBlinkLocked(r);
+        Mockito.reset(mVibrator);
+
+        // stop making noise - this is a weird corner case, but quiet should override once
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopVibrate();
+    }
+
+    @SmallTest
+    public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+        NotificationRecord s = getQuietNotification();
+
+        // the phone is quiet
+        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        // quiet update should stop making noise
+        mService.buzzBeepBlinkLocked(s);
+        verifyStopVibrate();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
deleted file mode 100644
index c44ffa4..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutInfoTest.java
+++ /dev/null
@@ -1,271 +0,0 @@
-
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.pm;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.PersistableBundle;
-import android.test.AndroidTestCase;
-
-import com.android.internal.util.Preconditions;
-import com.android.server.testutis.TestUtils;
-
-/**
- * Tests for {@link ShortcutInfo}.
-
- m FrameworksServicesTests &&
- adb install \
-   -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
- adb shell am instrument -e class com.android.server.pm.ShortcutInfoTest \
-   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
-
- */
-public class ShortcutInfoTest extends AndroidTestCase {
-
-    public void testMissingMandatoryFields() {
-        TestUtils.assertExpectException(
-                IllegalArgumentException.class,
-                "ID must be provided",
-                () -> new ShortcutInfo.Builder(mContext).build());
-        TestUtils.assertExpectException(
-                IllegalArgumentException.class,
-                "title must be provided",
-                () -> new ShortcutInfo.Builder(mContext).setId("id").build()
-                        .enforceMandatoryFields());
-        TestUtils.assertExpectException(
-                NullPointerException.class,
-                "Intent must be provided",
-                () -> new ShortcutInfo.Builder(mContext).setId("id").setTitle("x").build()
-                        .enforceMandatoryFields());
-    }
-
-    private ShortcutInfo parceled(ShortcutInfo si) {
-        Parcel p = Parcel.obtain();
-        p.writeParcelable(si, 0);
-        p.setDataPosition(0);
-        ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
-        p.recycle();
-        return si2;
-    }
-
-    private Intent makeIntent(String action, Object... bundleKeysAndValues) {
-        final Intent intent = new Intent(action);
-        intent.replaceExtras(ShortcutManagerTest.makeBundle(bundleKeysAndValues));
-        return intent;
-    }
-
-    public void testParcel() {
-        ShortcutInfo si = parceled(new ShortcutInfo.Builder(getContext())
-                .setId("id")
-                .setTitle("title")
-                .setIntent(makeIntent("action"))
-                .build());
-        assertEquals(getContext().getPackageName(), si.getPackageName());
-        assertEquals("id", si.getId());
-        assertEquals("title", si.getTitle());
-        assertEquals("action", si.getIntent().getAction());
-
-        PersistableBundle pb = new PersistableBundle();
-        pb.putInt("k", 1);
-
-        si = new ShortcutInfo.Builder(getContext())
-                .setId("id")
-                .setActivityComponent(new ComponentName("a", "b"))
-                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
-                .setTitle("title")
-                .setText("text")
-                .setIntent(makeIntent("action", "key", "val"))
-                .setWeight(123)
-                .setExtras(pb)
-                .build();
-        si.addFlags(ShortcutInfo.FLAG_PINNED);
-        si.setBitmapPath("abc");
-        si.setIconResourceId(456);
-
-        si = parceled(si);
-
-        assertEquals(getContext().getPackageName(), si.getPackageName());
-        assertEquals("id", si.getId());
-        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
-        assertEquals("content://a.b.c/", si.getIcon().getUriString());
-        assertEquals("title", si.getTitle());
-        assertEquals("text", si.getText());
-        assertEquals("action", si.getIntent().getAction());
-        assertEquals("val", si.getIntent().getStringExtra("key"));
-        assertEquals(123, si.getWeight());
-        assertEquals(1, si.getExtras().getInt("k"));
-
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
-        assertEquals("abc", si.getBitmapPath());
-        assertEquals(456, si.getIconResourceId());
-    }
-
-    public void testClone() {
-        PersistableBundle pb = new PersistableBundle();
-        pb.putInt("k", 1);
-        ShortcutInfo sorig = new ShortcutInfo.Builder(getContext())
-                .setId("id")
-                .setActivityComponent(new ComponentName("a", "b"))
-                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
-                .setTitle("title")
-                .setText("text")
-                .setIntent(makeIntent("action", "key", "val"))
-                .setWeight(123)
-                .setExtras(pb)
-                .build();
-        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
-        sorig.setBitmapPath("abc");
-        sorig.setIconResourceId(456);
-
-        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
-
-        assertEquals(getContext().getPackageName(), si.getPackageName());
-        assertEquals("id", si.getId());
-        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
-        assertEquals("content://a.b.c/", si.getIcon().getUriString());
-        assertEquals("title", si.getTitle());
-        assertEquals("text", si.getText());
-        assertEquals("action", si.getIntent().getAction());
-        assertEquals("val", si.getIntent().getStringExtra("key"));
-        assertEquals(123, si.getWeight());
-        assertEquals(1, si.getExtras().getInt("k"));
-
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
-        assertEquals("abc", si.getBitmapPath());
-        assertEquals(456, si.getIconResourceId());
-
-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
-
-        assertEquals(getContext().getPackageName(), si.getPackageName());
-        assertEquals("id", si.getId());
-        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
-        assertEquals(null, si.getIcon());
-        assertEquals("title", si.getTitle());
-        assertEquals("text", si.getText());
-        assertEquals("action", si.getIntent().getAction());
-        assertEquals("val", si.getIntent().getStringExtra("key"));
-        assertEquals(123, si.getWeight());
-        assertEquals(1, si.getExtras().getInt("k"));
-
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
-        assertEquals(null, si.getBitmapPath());
-        assertEquals(0, si.getIconResourceId());
-
-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
-
-        assertEquals(getContext().getPackageName(), si.getPackageName());
-        assertEquals("id", si.getId());
-        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
-        assertEquals(null, si.getIcon());
-        assertEquals("title", si.getTitle());
-        assertEquals("text", si.getText());
-        assertEquals(null, si.getIntent());
-        assertEquals(123, si.getWeight());
-        assertEquals(1, si.getExtras().getInt("k"));
-
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
-        assertEquals(null, si.getBitmapPath());
-        assertEquals(0, si.getIconResourceId());
-
-        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
-
-        assertEquals(getContext().getPackageName(), si.getPackageName());
-        assertEquals("id", si.getId());
-        assertEquals(null, si.getActivityComponent());
-        assertEquals(null, si.getIcon());
-        assertEquals(null, si.getTitle());
-        assertEquals(null, si.getText());
-        assertEquals(null, si.getIntent());
-        assertEquals(0, si.getWeight());
-        assertEquals(null, si.getExtras());
-
-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
-        assertEquals(null, si.getBitmapPath());
-        assertEquals(0, si.getIconResourceId());
-    }
-
-
-    public void testCopyNonNullFieldsFrom() {
-        PersistableBundle pb = new PersistableBundle();
-        pb.putInt("k", 1);
-        ShortcutInfo sorig = new ShortcutInfo.Builder(getContext())
-                .setId("id")
-                .setActivityComponent(new ComponentName("a", "b"))
-                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
-                .setTitle("title")
-                .setText("text")
-                .setIntent(makeIntent("action", "key", "val"))
-                .setWeight(123)
-                .setExtras(pb)
-                .build();
-        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
-        sorig.setBitmapPath("abc");
-        sorig.setIconResourceId(456);
-
-        ShortcutInfo si;
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setActivityComponent(new ComponentName("x", "y")).build());
-        assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
-        assertEquals("content://x.y.z/", si.getIcon().getUriString());
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setTitle("xyz").build());
-        assertEquals("xyz", si.getTitle());
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setText("xxx").build());
-        assertEquals("xxx", si.getText());
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setIntent(makeIntent("action2")).build());
-        assertEquals("action2", si.getIntent().getAction());
-        assertEquals(null, si.getIntent().getStringExtra("key"));
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setIntent(makeIntent("action3", "key", "x")).build());
-        assertEquals("action3", si.getIntent().getAction());
-        assertEquals("x", si.getIntent().getStringExtra("key"));
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setWeight(999).build());
-        assertEquals(999, si.getWeight());
-
-
-        PersistableBundle pb2 = new PersistableBundle();
-        pb2.putInt("x", 99);
-
-        si = sorig.clone(/* flags=*/ 0);
-        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getContext()).setId("id")
-                .setExtras(pb2).build());
-        assertEquals(99, si.getExtras().getInt("x"));
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index 5d29242..baa5d36 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -16,8 +16,11 @@
 package com.android.server.pm;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyList;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
@@ -46,6 +49,7 @@
 import android.content.pm.ShortcutManager;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.Signature;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
@@ -57,7 +61,9 @@
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -66,6 +72,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.frameworks.servicestests.R;
@@ -76,6 +83,7 @@
 import com.android.server.pm.ShortcutService.ConfigConstants;
 import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
 import com.android.server.pm.ShortcutUser.PackageWithUser;
+import com.android.server.testutis.TestUtils;
 
 import libcore.io.IoUtils;
 
@@ -96,6 +104,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
 
 /**
  * Tests for ShortcutService and ShortcutManager.
@@ -107,10 +117,8 @@
  -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 
  * TODO: Add checks with assertAllNotHaveIcon()
- *
- * TODO: separate, detailed tests for ShortcutInfo (CTS?) *
- *
- * TODO: Cross-user test (do in CTS?)
+ * TODO: Detailed test for hasShortcutPermissionInner().
+ * TODO: Add tests for the command line functions too.
  */
 @SmallTest
 public class ShortcutManagerTest extends InstrumentationTestCase {
@@ -122,6 +130,8 @@
      */
     private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
 
+    private static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
     // public for mockito
     public class BaseContext extends MockContext {
         @Override
@@ -260,8 +270,7 @@
 
         @Override
         boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
-            // Sort of hack; do a simpler check.
-            return LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage);
+            return mDefaultLauncherChecker.test(callingPackage, userId);
         }
 
         @Override
@@ -279,12 +288,7 @@
         @Override
         void postToHandler(Runnable r) {
             final long token = mContext.injectClearCallingIdentity();
-            super.postToHandler(r);
-            try {
-                runTestOnUiThread(() -> {});
-            } catch (Throwable e) {
-                fail("runTestOnUiThread failed: " + e);
-            }
+            r.run();
             mContext.injectRestoreCallingIdentity(token);
         }
 
@@ -316,36 +320,11 @@
         }
 
         @Override
-        public void ensureInUserProfiles(UserHandle userToCheck, String message) {
-            if (getCallingUserId() == userToCheck.getIdentifier()) {
-                return; // okay
-            }
-            if (getCallingUserId() == USER_0 && userToCheck.getIdentifier() == USER_P0) {
-                return; // profile, okay.
-            }
-            if (getCallingUserId() == USER_P0 && userToCheck.getIdentifier() == USER_0) {
-                return; // profile, okay.
-            }
-
-            if (mInjectedCallingUid != Process.SYSTEM_UID) {
-                throw new SecurityException("To access other users, you need to be SYSTEM" +
-                        ", but current UID=" + mInjectedCallingUid);
-            }
-        }
-
-        @Override
         public void verifyCallingPackage(String callingPackage) {
             // SKIP
         }
 
         @Override
-        boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) {
-            // This requires CROSS_USER
-            assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
-            return user.getIdentifier() == listeningUser.getIdentifier();
-        }
-
-        @Override
         void postToPackageMonitorHandler(Runnable r) {
             final long token = mContext.injectClearCallingIdentity();
             r.run();
@@ -356,6 +335,18 @@
         int injectBinderCallingUid() {
             return mInjectedCallingUid;
         }
+
+        @Override
+        long injectClearCallingIdentity() {
+            final int prevCallingUid = mInjectedCallingUid;
+            mInjectedCallingUid = Process.SYSTEM_UID;
+            return prevCallingUid;
+        }
+
+        @Override
+        void injectRestoreCallingIdentity(long token) {
+            mInjectedCallingUid = (int) token;
+        }
     }
 
     private class LauncherAppsTestable extends LauncherApps {
@@ -381,7 +372,11 @@
     private ShortcutServiceInternal mInternal;
 
     private LauncherAppImplTestable mLauncherAppImpl;
-    private LauncherAppsTestable mLauncherApps;
+
+    // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
+    private final Map<Pair<Integer, String>, LauncherAppsTestable>
+            mLauncherAppsMap = new HashMap<>();
+    private LauncherAppsTestable mLauncherApps; // Current one
 
     private File mInjectedFilePathRoot;
 
@@ -394,7 +389,7 @@
 
     private Map<String, PackageInfo> mInjectedPackages;
 
-    private ArrayList<PackageWithUser> mUninstalledPackages;
+    private Set<PackageWithUser> mUninstalledPackages;
 
     private PackageManager mMockPackageManager;
     private PackageManagerInternal mMockPackageManagerInternal;
@@ -409,12 +404,21 @@
     private static final String CALLING_PACKAGE_3 = "com.android.test.3";
     private static final int CALLING_UID_3 = 10003;
 
+    private static final String CALLING_PACKAGE_4 = "com.android.test.4";
+    private static final int CALLING_UID_4 = 10004;
+
     private static final String LAUNCHER_1 = "com.android.launcher.1";
     private static final int LAUNCHER_UID_1 = 10011;
 
     private static final String LAUNCHER_2 = "com.android.launcher.2";
     private static final int LAUNCHER_UID_2 = 10012;
 
+    private static final String LAUNCHER_3 = "com.android.launcher.3";
+    private static final int LAUNCHER_UID_3 = 10013;
+
+    private static final String LAUNCHER_4 = "com.android.launcher.4";
+    private static final int LAUNCHER_UID_4 = 10014;
+
     private static final int USER_0 = UserHandle.USER_SYSTEM;
     private static final int USER_10 = 10;
     private static final int USER_11 = 11;
@@ -425,6 +429,24 @@
     private static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
     private static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
 
+    private static final UserInfo USER_INFO_0 = withProfileGroupId(
+            new UserInfo(USER_0, "user0",
+                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
+
+    private static final UserInfo USER_INFO_10 =
+            new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
+
+    private static final UserInfo USER_INFO_11 =
+            new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
+
+    private static final UserInfo USER_INFO_P0 = withProfileGroupId(
+            new UserInfo(USER_P0, "userP0",
+                    UserInfo.FLAG_MANAGED_PROFILE), 10);
+
+    private BiPredicate<String, Integer> mDefaultLauncherChecker =
+            (callingPackage, userId) ->
+            LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
+            || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
 
     private static final long START_TIME = 1440000000101L;
 
@@ -438,6 +460,13 @@
 
     private static final int MAX_ICON_DIMENSION_LOWRAM = 32;
 
+    private static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
+
+    static {
+        QUERY_ALL.setQueryFlags(
+                ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -457,30 +486,83 @@
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
         addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
         addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
+        addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
         addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
+        addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
+        addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
 
-        mUninstalledPackages = new ArrayList<>();
+        // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
+        updatePackageInfo(CALLING_PACKAGE_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+        updatePackageInfo(LAUNCHER_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        mUninstalledPackages = new HashSet<>();
 
         mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
 
-        // Empty the data directory.
-        if (mInjectedFilePathRoot.exists()) {
-            Assert.assertTrue("failed to delete dir",
-                    FileUtils.deleteContents(mInjectedFilePathRoot));
-        }
-        mInjectedFilePathRoot.mkdirs();
+        deleteAllSavedFiles();
+
+        // Set up users.
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_0;
+        }).when(mMockUserManager).getUserInfo(eq(USER_0));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_10;
+        }).when(mMockUserManager).getUserInfo(eq(USER_10));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_11;
+        }).when(mMockUserManager).getUserInfo(eq(USER_11));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_P0;
+        }).when(mMockUserManager).getUserInfo(eq(USER_P0));
+
+        // User 0 is always running.
+        when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
 
         initService();
         setCaller(CALLING_PACKAGE_1);
     }
 
+    private static UserInfo withProfileGroupId(UserInfo in, int groupId) {
+        in.profileGroupId = groupId;
+        return in;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
+
+        shutdownServices();
+
+        super.tearDown();
+    }
+
     private Context getTestContext() {
         return getInstrumentation().getContext();
     }
 
+    private void deleteAllSavedFiles() {
+        // Empty the data directory.
+        if (mInjectedFilePathRoot.exists()) {
+            Assert.assertTrue("failed to delete dir",
+                    FileUtils.deleteContents(mInjectedFilePathRoot));
+        }
+        mInjectedFilePathRoot.mkdirs();
+    }
+
     /** (Re-) init the manager and the service. */
     private void initService() {
+        shutdownServices();
+
         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
 
         // Instantiate targets.
@@ -490,12 +572,28 @@
         mInternal = LocalServices.getService(ShortcutServiceInternal.class);
 
         mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
-        mLauncherApps = new LauncherAppsTestable(mClientContext, mLauncherAppImpl);
+        mLauncherApps = null;
+        mLauncherAppsMap.clear();
 
         // Load the setting file.
         mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
     }
 
+    private void shutdownServices() {
+        if (mService != null) {
+            // Flush all the unsaved data from the previous instance.
+            mService.saveDirtyInfo();
+        }
+        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+        mService = null;
+        mManager = null;
+        mInternal = null;
+        mLauncherAppImpl = null;
+        mLauncherApps = null;
+        mLauncherAppsMap.clear();
+    }
+
     private void addPackage(String packageName, int uid, int version) {
         addPackage(packageName, uid, version, packageName);
     }
@@ -504,6 +602,10 @@
         return Arrays.asList(array);
     }
 
+    private <T> Set<T> set(Set<T> in) {
+        return new ArraySet<T>(in);
+    }
+
     private Signature[] genSignatures(String... signatures) {
         final Signature[] sigs = new Signature[signatures.length];
         for (int i = 0; i < signatures.length; i++){
@@ -529,10 +631,24 @@
         mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
     }
 
+    private void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
+        c.accept(mInjectedPackages.get(packageName));
+    }
+
     private void uninstallPackage(int userId, String packageName) {
+        if (ENABLE_DUMP) {
+            Log.i(TAG, "Unnstall package " + packageName + " / " + userId);
+        }
         mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
     }
 
+    private void installPackage(int userId, String packageName) {
+        if (ENABLE_DUMP) {
+            Log.i(TAG, "Install package " + packageName + " / " + userId);
+        }
+        mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
+    }
+
     PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
             boolean getSignatures) {
         final PackageInfo pi = mInjectedPackages.get(packageName);
@@ -560,6 +676,13 @@
         mInjectedCallingUid =
                 Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
                         "Unknown package").applicationInfo.uid;
+
+        // Set up LauncherApps for this caller.
+        final Pair<Integer, String> key = Pair.create(userId, packageName);
+        if (!mLauncherAppsMap.containsKey(key)) {
+            mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
+        }
+        mLauncherApps = mLauncherAppsMap.get(key);
     }
 
     private void setCaller(String packageName) {
@@ -570,6 +693,10 @@
         return mInjectedClientPackage;
     }
 
+    private void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
+        mDefaultLauncherChecker = p;
+    }
+
     private void runWithCaller(String packageName, int userId, Runnable r) {
         final String previousPackage = mInjectedClientPackage;
         final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
@@ -591,14 +718,22 @@
 
     /** For debugging */
     private void dumpsysOnLogcat() {
-        if (!ENABLE_DUMP) return;
+        dumpsysOnLogcat("");
+    }
+
+    private void dumpsysOnLogcat(String message) {
+        dumpsysOnLogcat(message, false);
+    }
+
+    private void dumpsysOnLogcat(String message, boolean force) {
+        if (force || !ENABLE_DUMP) return;
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         final PrintWriter pw = new PrintWriter(out);
         mService.dumpInner(pw);
         pw.close();
 
-        Log.e(TAG, "Dumping ShortcutService:");
+        Log.e(TAG, "Dumping ShortcutService: " + message);
         for (String line : out.toString().split("\n")) {
             Log.e(TAG, line);
         }
@@ -608,9 +743,13 @@
      * For debugging, dump arbitrary file on logcat.
      */
     private void dumpFileOnLogcat(String path) {
+        dumpFileOnLogcat(path, "");
+    }
+
+    private void dumpFileOnLogcat(String path, String message) {
         if (!ENABLE_DUMP) return;
 
-        Log.i(TAG, "Dumping file: " + path);
+        Log.i(TAG, "Dumping file: " + path + " " + message);
         final StringBuilder sb = new StringBuilder();
         try (BufferedReader br = new BufferedReader(new FileReader(path))) {
             String line;
@@ -636,10 +775,14 @@
      * For debugging, dump per-user state file on logcat.
      */
     private void dumpUserFile(int userId) {
+        dumpUserFile(userId, "");
+    }
+
+    private void dumpUserFile(int userId, String message) {
         mService.saveDirtyInfo();
         dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
                 + "/user-" + userId
-                + "/" + ShortcutService.FILENAME_USER_PACKAGES);
+                + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
     }
 
     private void waitOnMainThread() throws Throwable {
@@ -778,6 +921,12 @@
         return ret;
     }
 
+    private static void resetAll(Collection<?> mocks) {
+        for (Object o : mocks) {
+            reset(o);
+        }
+    }
+
     @NonNull
     private ShortcutInfo findById(List<ShortcutInfo> list, String id) {
         for (ShortcutInfo s : list) {
@@ -789,6 +938,10 @@
         return null;
     }
 
+    private void assertSystem() {
+        assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
+    }
+
     private void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
         assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
         assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
@@ -877,7 +1030,7 @@
     private List<ShortcutInfo> assertAllHaveIcon(
             @NonNull List<ShortcutInfo> actualShortcuts) {
         for (ShortcutInfo s : actualShortcuts) {
-            assertTrue("ID " + s.getId(), s.hasIconFile() || s.hasIconResource());
+            assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
         }
         return actualShortcuts;
     }
@@ -886,7 +1039,8 @@
     private List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
             int shortcutFlags) {
         for (ShortcutInfo s : actualShortcuts) {
-            assertTrue("ID " + s.getId(), s.hasFlags(shortcutFlags));
+            assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
+                    s.hasFlags(shortcutFlags));
         }
         return actualShortcuts;
     }
@@ -1055,11 +1209,13 @@
         return i;
     }
 
-    /**
-     * Wrap a set in an ArraySet just to get a better toString.
-     */
-    private <T> Set<T> set(Set<T> in) {
-        return new ArraySet<T>(in);
+    private ShortcutInfo parceled(ShortcutInfo si) {
+        Parcel p = Parcel.obtain();
+        p.writeParcelable(si, 0);
+        p.setDataPosition(0);
+        ShortcutInfo si2 = p.readParcelable(getClass().getClassLoader());
+        p.recycle();
+        return si2;
     }
 
     /**
@@ -1320,8 +1476,6 @@
 
         // Still 2 calls left.
         assertEquals(2, mManager.getRemainingCallCount());
-
-        // TODO Make sure pinned shortcuts won't be deleted.
     }
 
     public void testDeleteAllDynamicShortcuts() {
@@ -1351,8 +1505,6 @@
 
         // Still 1 call left
         assertEquals(1, mManager.getRemainingCallCount());
-
-        // TODO Make sure pinned shortcuts won't be deleted.
     }
 
     public void testThrottling() {
@@ -1877,9 +2029,6 @@
         });
     }
 
-    // TODO: updateShortcuts()
-    // TODO: getPinnedShortcuts()
-
     // === Test for launcher side APIs ===
 
     private static ShortcutQuery buildQuery(long changedSince,
@@ -1893,6 +2042,20 @@
         return q;
     }
 
+    private static ShortcutQuery buildAllQuery(String packageName) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setPackage(packageName);
+        q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+        return q;
+    }
+
+    private static ShortcutQuery buildPinnedQuery(String packageName) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setPackage(packageName);
+        q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
+        return q;
+    }
+
     public void testGetShortcuts() {
 
         // Set up shortcuts.
@@ -2928,12 +3091,6 @@
     }
 
     public void testLauncherCallback() throws Throwable {
-
-        // TODO Add "multi" version -- run the test with two launchers and make sure the callback
-        // argument only contains the ones that are actually visible to each launcher.
-
-        when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
-
         LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
 
         // Set listeners
@@ -2989,6 +3146,7 @@
         // Test for addDynamicShortcut.
         reset(c0);
         runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            dumpsysOnLogcat("before addDynamicShortcut");
             assertTrue(mManager.addDynamicShortcut(makeShortcut("s4")));
         });
 
@@ -3052,6 +3210,7 @@
 
         // Remove CALLING_PACKAGE_2
         reset(c0);
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
         mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0);
 
         // Should get a callback with an empty list.
@@ -3065,6 +3224,156 @@
         assertEquals(0, shortcuts.getValue().size());
     }
 
+    private void assertCallbackNotReceived(LauncherApps.Callback mock) {
+        verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
+                any(UserHandle.class));
+    }
+
+    private void assertCallbackReceived(LauncherApps.Callback mock,
+            UserHandle user, String packageName, String... ids) {
+        ArgumentCaptor<List> shortcutsCaptor = ArgumentCaptor.forClass(List.class);
+
+        verify(mock, times(1)).onShortcutsChanged(eq(packageName), shortcutsCaptor.capture(),
+                eq(user));
+        assertShortcutIds(shortcutsCaptor.getValue(), ids);
+    }
+
+    public void testLauncherCallback_crossProfile() throws Throwable {
+        prepareCrossProfileDataSet();
+
+        final Handler h = new Handler(Looper.getMainLooper());
+
+        final LauncherApps.Callback c0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_2 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_3 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
+
+        final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
+
+        final List<LauncherApps.Callback> all =
+                list(c0_1, c0_2, c0_3, c0_4, cP0_1, c10_1, c11_1);
+
+        setDefaultLauncherChecker((pkg, userId) -> {
+            switch (userId) {
+                case USER_0:
+                    return LAUNCHER_2.equals(pkg);
+                case USER_P0:
+                    return LAUNCHER_1.equals(pkg);
+                case USER_10:
+                    return LAUNCHER_1.equals(pkg);
+                case USER_11:
+                    return LAUNCHER_1.equals(pkg);
+                default:
+                    return false;
+            }
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h));
+        runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h));
+        runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
+        runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
+        runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
+        runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
+        runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
+        runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
+
+        // User 0.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
+        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+        // User 0, different package.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
+        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
+                "s1", "s2", "s3", "s4", "s5", "s6");
+
+        // Work profile, but not running, so don't send notifications.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_2);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(cP0_1);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+
+        // Work profile, now running.
+
+        when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+        when(mMockUserManager.isUserRunning(eq(USER_P0))).thenReturn(true);
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
+        assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+        // Normal secondary user.
+
+        when(mMockUserManager.isUserRunning(anyInt())).thenReturn(false);
+        when(mMockUserManager.isUserRunning(eq(USER_10))).thenReturn(true);
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            mManager.deleteDynamicShortcut("x");
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_2);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(cP0_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
+                "x1", "x2", "x3", "x4", "x5");
+    }
+
     // === Test for persisting ===
 
     public void testSaveAndLoadUser_empty() {
@@ -3299,9 +3608,9 @@
         // Check the registered packages.
         dumpsysOnLogcat();
         assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3326,13 +3635,14 @@
         mService.saveDirtyInfo();
 
         // Nonexistent package.
+        uninstallPackage(USER_0, "abc");
         mService.cleanUpPackageLocked("abc", USER_0, USER_0);
 
         // No changes.
         assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3357,12 +3667,13 @@
         mService.saveDirtyInfo();
 
         // Remove a package.
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
         mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
 
         assertEquals(makeSet(CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3387,12 +3698,13 @@
         mService.saveDirtyInfo();
 
         // Remove a launcher.
+        uninstallPackage(USER_10, LAUNCHER_1);
         mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
 
         assertEquals(makeSet(CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3414,12 +3726,13 @@
         mService.saveDirtyInfo();
 
         // Remove a package.
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
         mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
 
         assertEquals(makeSet(CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(CALLING_PACKAGE_1),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3441,12 +3754,13 @@
         mService.saveDirtyInfo();
 
         // Remove the other launcher from user 10 too.
+        uninstallPackage(USER_10, LAUNCHER_2);
         mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
 
         assertEquals(makeSet(CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(CALLING_PACKAGE_1),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3468,12 +3782,13 @@
         mService.saveDirtyInfo();
 
         // More remove.
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
         mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
 
         assertEquals(makeSet(CALLING_PACKAGE_2),
-                set(user0.getPackages().keySet()));
+                set(user0.getAllPackages().keySet()));
         assertEquals(makeSet(),
-                set(user10.getPackages().keySet()));
+                set(user10.getAllPackages().keySet()));
         assertEquals(
                 makeSet(PackageWithUser.of(USER_0, LAUNCHER_1),
                         PackageWithUser.of(USER_0, LAUNCHER_2)),
@@ -3494,97 +3809,6 @@
         mService.saveDirtyInfo();
     }
 
-
-    public void testSaveAndLoadUser_forBackup() {
-        // Create some shortcuts.
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(
-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
-        });
-        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(
-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
-        });
-        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(
-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
-        });
-        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(
-                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
-        });
-
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
-
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
-
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
-
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
-
-        // Pin some.
-
-        runWithCaller(LAUNCHER_1, USER_0, () -> {
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                    list("s1"), HANDLE_USER_0);
-
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                    list("s2"), UserHandle.of(USER_P0));
-
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
-                    list("s3"), HANDLE_USER_0);
-        });
-
-        runWithCaller(LAUNCHER_1, USER_P0, () -> {
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                    list("s2"), HANDLE_USER_0);
-
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                    list("s3"), UserHandle.of(USER_P0));
-
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
-                    list("s1"), HANDLE_USER_0);
-        });
-
-        runWithCaller(LAUNCHER_1, USER_10, () -> {
-            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
-                    list("s3"), HANDLE_USER_10);
-        });
-
-        // Check the state.
-
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
-
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
-
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
-
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
-        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
-        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
-
-        // Make sure all the information is persisted.
-        mService.saveDirtyInfo();
-        initService();
-        mService.handleUnlockUser(USER_0);
-        mService.handleUnlockUser(USER_P0);
-        mService.handleUnlockUser(USER_10);
-    }
-
     public void testHandleGonePackage_crossProfile() {
         // Create some shortcuts.
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3841,13 +4065,9 @@
         assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
     }
 
-    // TODO Detailed test for hasShortcutPermissionInner().
-
-    // TODO Add tests for the command line functions too.
-
     private void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
             int version, String... signatures) {
-        assertEquals(expected, spi.canRestoreTo(genPackage(
+        assertEquals(expected, spi.canRestoreTo(mService, genPackage(
                 "dummy", /* uid */ 0, version, signatures)));
     }
 
@@ -3919,6 +4139,7 @@
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
 
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
         mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
 
@@ -3929,6 +4150,7 @@
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
 
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
         mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
 
@@ -3961,7 +4183,1193 @@
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
     }
 
-    public void testHandlePackageUpdate() {
-        // TODO: Make sure unshadow is called.
+    private void backupAndRestore() {
+        int prevUid = mInjectedCallingUid;
+
+        mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
+
+        dumpsysOnLogcat("Before backup");
+
+        final byte[] payload =  mService.getBackupPayload(USER_0);
+        if (ENABLE_DUMP) {
+            final String xml = new String(payload);
+            Log.i(TAG, "Backup payload:");
+            for (String line : xml.split("\n")) {
+                Log.i(TAG, line);
+            }
+        }
+
+        // Before doing anything else, uninstall all packages.
+        for (int userId : list(USER_0, USER_P0)) {
+            for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
+                    LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
+                uninstallPackage(userId, pkg);
+            }
+        }
+
+        shutdownServices();
+
+        deleteAllSavedFiles();
+
+        initService();
+        mService.applyRestore(payload, USER_0);
+
+        // handleUnlockUser will perform the gone package check, but it shouldn't remove
+        // shadow information.
+        mService.handleUnlockUser(USER_0);
+
+        dumpsysOnLogcat("After restore");
+
+        mInjectedCallingUid = prevUid;
+    }
+
+    private void prepareCrossProfileDataSet() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list()));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
+                    makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_3, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_4, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
+        });
+
+        // Launcher on a managed profile is referring ot user 0!
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
+                    HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
+                    HANDLE_USER_10);
+        });
+
+        // Then remove some dynamic shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list()));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
+        });
+    }
+
+    private void prepareForBackupTest() {
+
+        prepareCrossProfileDataSet();
+
+        backupAndRestore();
+    }
+
+    private void assertExistsAndShadow(ShortcutPackageItem spi) {
+        assertNotNull(spi);
+        assertTrue(spi.getPackageInfo().isShadow());
+    }
+
+    /**
+     * Make sure the backup data doesn't have the following information:
+     * - Launchers on other users.
+     * - Non-backup app information.
+     *
+     * But restores all other infomation.
+     *
+     * It also omits the following pieces of information, but that's tested in
+     * {@link #testShortcutInfoSaveAndLoad_forBackup}.
+     * - Unpinned dynamic shortcuts
+     * - Bitmaps
+     */
+    public void testBackupAndRestore() {
+        prepareForBackupTest();
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_backupRestoreTwice() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        dumpsysOnLogcat("Before second backup");
+
+        backupAndRestore();
+
+        dumpsysOnLogcat("After second backup");
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_backupRestoreMultiple() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        // This also shouldn't affect the result.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+
+        backupAndRestore();
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_restoreToNewVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_restoreToSuperSetSignatures() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        // Change package signatures.
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
+
+        checkBackupAndRestore_success();
+    }
+
+    private void checkBackupAndRestore_success() {
+        // Make sure non-system user is not restored.
+        final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
+        assertEquals(0, userP0.getAllPackages().size());
+        assertEquals(0, userP0.getAllLaunchers().size());
+
+        // Make sure only "allowBackup" apps are restored, and are shadow.
+        final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
+        assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_1));
+        assertExistsAndShadow(user0.getAllPackages().get(CALLING_PACKAGE_2));
+        assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_1)));
+        assertExistsAndShadow(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_2)));
+
+        assertNull(user0.getAllPackages().get(CALLING_PACKAGE_3));
+        assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
+        assertNull(user0.getAllLaunchers().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty, not restored */ );
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty, not restored */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty, not restored */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        // 3 shouldn't be backed up, so no pinned shortcuts.
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        // Launcher on a different profile shouldn't be restored.
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+                    .size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+                            .size());
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+        });
+
+        // Package on a different profile, no restore.
+        installPackage(USER_P0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        // Restore launcher 2 on user 0.
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+
+        // Restoration of launcher2 shouldn't affect other packages; so do the same checks and
+        // make sure they still have the same result.
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+    }
+
+    public void testBackupAndRestore_publisherLowerVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    public void testBackupAndRestore_publisherWrongSignature() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    public void testBackupAndRestore_publisherNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(CALLING_PACKAGE_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    private void checkBackupAndRestore_publisherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testBackupAndRestore_launcherLowerVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    public void testBackupAndRestore_launcherWrongSignature() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    public void testBackupAndRestore_launcherNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(LAUNCHER_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    private void checkBackupAndRestore_launcherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+
+            // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here.
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        // Now we try to restore launcher 1.  Then we realize it's not restorable, so L1 has no pinned
+        // shortcuts.
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+
+            // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned.
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(CALLING_PACKAGE_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        updatePackageInfo(LAUNCHER_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_publisherAndLauncherNotRestored();
+    }
+
+    private void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        // Because launcher 1 wasn't restored, "s1" is no longer pinned.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testSaveAndLoad_crossProfile() {
+        prepareCrossProfileDataSet();
+
+        dumpsysOnLogcat("Before save & load");
+
+        mService.saveDirtyInfo();
+        initService();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5");
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+                    /* empty */);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_P0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+                    /* empty */);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "x1", "x2", "x3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "x4", "x5");
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s1");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s1", "s2");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s1", "s2", "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s1", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+            TestUtils.assertExpectException(
+                    SecurityException.class, "", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+                    });
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s2");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s2", "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s2", "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s2", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_3, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s3", "s4", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s3", "s6");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_4, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s3", "s4", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s3", "s4", "s5", "s6");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s1", "s4");
+            TestUtils.assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+                    });
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10),
+                    "x4", "x5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
+                    /* empty */);
+            TestUtils.assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
+                    });
+            TestUtils.assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
+                    });
+        });
+    }
+
+    // ShortcutInfo tests
+
+    public void testShortcutInfoMissingMandatoryFields() {
+        TestUtils.assertExpectException(
+                IllegalArgumentException.class,
+                "ID must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).build());
+        TestUtils.assertExpectException(
+                IllegalArgumentException.class,
+                "title must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
+                        .enforceMandatoryFields());
+        TestUtils.assertExpectException(
+                NullPointerException.class,
+                "Intent must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id").setTitle("x").build()
+                        .enforceMandatoryFields());
+    }
+
+    public void testShortcutInfoParcel() {
+        ShortcutInfo si = parceled(new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setTitle("title")
+                .setIntent(makeIntent("action", ShortcutActivity.class))
+                .build());
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals("title", si.getTitle());
+        assertEquals("action", si.getIntent().getAction());
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+
+        si = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivityComponent(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+        si.addFlags(ShortcutInfo.FLAG_PINNED);
+        si.setBitmapPath("abc");
+        si.setIconResourceId(456);
+
+        si = parceled(si);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals("content://a.b.c/", si.getIcon().getUriString());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoClone() {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivityComponent(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals("content://a.b.c/", si.getIcon().getUriString());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+        assertEquals(0, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals(null, si.getIntent());
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+        assertEquals(0, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(null, si.getActivityComponent());
+        assertEquals(null, si.getIcon());
+        assertEquals(null, si.getTitle());
+        assertEquals(null, si.getText());
+        assertEquals(null, si.getIntent());
+        assertEquals(0, si.getWeight());
+        assertEquals(null, si.getExtras());
+
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+        assertEquals(0, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivityComponent(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithContentUri("content://a.b.c/"))
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si;
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setActivityComponent(new ComponentName("x", "y")).build());
+        assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+        assertEquals("content://x.y.z/", si.getIcon().getUriString());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+        assertEquals("xyz", si.getTitle());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setText("xxx").build());
+        assertEquals("xxx", si.getText());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+        assertEquals("action2", si.getIntent().getAction());
+        assertEquals(null, si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+        assertEquals("action3", si.getIntent().getAction());
+        assertEquals("x", si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setWeight(999).build());
+        assertEquals(999, si.getWeight());
+
+
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("x", 99);
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setExtras(pb2).build());
+        assertEquals(99, si.getExtras().getInt("x"));
+
+        final long timestamp = si.getLastChangedTimestamp();
+        Thread.sleep(2);
+
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+
+        assertTrue(si.getLastChangedTimestamp() > timestamp);
+    }
+
+    public void testShortcutInfoSaveAndLoad() throws InterruptedException {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcut(sorig);
+
+        Thread.sleep(2);
+        final long now = System.currentTimeMillis();
+
+        // Save and load.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+        assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
+        assertNotNull(si.getBitmapPath()); // Something should be set.
+        assertEquals(0, si.getIconResourceId());
+        assertTrue(si.getLastChangedTimestamp() < now);
+    }
+
+    public void testShortcutInfoSaveAndLoad_forBackup() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitle("title")
+                .setText("text")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setWeight(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcut(sorig);
+
+        // Dynamic shortcuts won't be backed up, so we need to pin it.
+        setCaller(LAUNCHER_1, USER_0);
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+
+        // Do backup & restore.
+        backupAndRestore();
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+        assertEquals(CALLING_PACKAGE_1, si.getPackageName());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getWeight());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertNull(si.getBitmapPath()); // No icon.
+        assertEquals(0, si.getIconResourceId());
+    }
+
+    public void testDumpsys_crossProfile() {
+        prepareCrossProfileDataSet();
+        dumpsysOnLogcat("test1", /* force= */ true);
+    }
+
+    public void testDumpsys_withIcons() {
+        testIcons();
+        // Dump after having some icons.
+        dumpsysOnLogcat("test1", /* force= */ true);
     }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index b56ce73..dbc2b0c 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -170,6 +170,15 @@
     public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
 
     /**
+     * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
+     * <p>
+     * When set, Telecom will allow emergency video calls to be placed.  When not set, Telecom will
+     * convert all outgoing video calls to emergency numbers to audio-only.
+     * @hide
+     */
+    public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
+
+    /**
      * URI scheme for telephone number URIs.
      */
     public static final String SCHEME_TEL = "tel";
@@ -731,6 +740,9 @@
         if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
             sb.append("PlaceEmerg ");
         }
+        if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
+            sb.append("EmergVideo ");
+        }
         if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
             sb.append("SimSub ");
         }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c69a360..461611d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -252,6 +252,16 @@
     public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
 
     /**
+     * Flag specifying whether WFC over IMS supports the "wifi only" option.  If false, the wifi
+     * calling settings will not include an option for "wifi only".  If true, the wifi calling
+     * settings will include an option for "wifi only"
+     * <p>
+     * By default, it is assumed that WFC supports "wifi only".
+     */
+    public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL =
+            "carrier_wfc_supports_wifi_only_bool";
+
+    /**
      * Default WFC_IMS_mode 0: WIFI_ONLY
      *                      1: CELLULAR_PREFERRED
      *                      2: WIFI_PREFERRED
@@ -628,6 +638,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
         sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index b739ead..c7cbf97 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -145,6 +145,7 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @removed */
     @Override
     public SharedPreferences getSharedPreferences(File file, int mode) {
         throw new UnsupportedOperationException();
@@ -180,6 +181,7 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @removed */
     @Override
     public File getSharedPreferencesPath(String name) {
         throw new UnsupportedOperationException();
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index ed7351f8..033312b 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -62,7 +62,7 @@
     private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
     private static final String WEARABLE_ACTION_GOOGLE =
             "com.google.android.wearable.action.GOOGLE";
-    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
+    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
     private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
     private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
 
diff --git a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
index cb77118..a169b18 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
@@ -1,35 +1,35 @@
-/*

- * Copyright (C) 2008 The Android Open Source Project

- *

- * Licensed under the Apache License, Version 2.0 (the "License");

- * you may not use this file except in compliance with the License.

- * You may obtain a copy of the License at

- *

- *      http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS,

- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

- * See the License for the specific language governing permissions and

- * limitations under the License.

- */

-

-package com.android.locationtracker;

-

-import android.os.Bundle;

-import android.preference.PreferenceActivity;

-

-/**

- * Settings preference screen for location tracker

- */

-public class SettingsActivity extends PreferenceActivity {

-

-    @Override

-    protected void onCreate(Bundle savedInstanceState) {

-        super.onCreate(savedInstanceState);

-

-        // Load the preferences from an XML resource

-        addPreferencesFromResource(R.xml.preferences);

-    }

-

-}

+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.locationtracker;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Settings preference screen for location tracker
+ */
+public class SettingsActivity extends PreferenceActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Load the preferences from an XML resource
+        addPreferencesFromResource(R.xml.preferences);
+    }
+
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
index 55d4d1e..adc39b3 100644
--- a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
@@ -1,75 +1,75 @@
-/*

- * Copyright (C) 2008 The Android Open Source Project

- *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not

- * use this file except in compliance with the License. You may obtain a copy of

- * the License at

- *

- * http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

- * License for the specific language governing permissions and limitations under

- * the License.

- */

-package com.android.locationtracker.data;

-

-import android.app.ListActivity;

-import android.content.Context;

-import android.database.Cursor;

-import android.view.View;

-import android.widget.ResourceCursorAdapter;

-import android.widget.TextView;

-

-import com.android.locationtracker.R;

-

-/**

- * Used to bind Tracker data to a list view UI

- */

-public class TrackerListHelper extends TrackerDataHelper {

-

-    private ListActivity mActivity;

-

-    // sort entries by most recent first

-    private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";

-

-    public TrackerListHelper(ListActivity activity) {

-        super(activity, TrackerDataHelper.CSV_FORMATTER);

-        mActivity = activity;

-    }

-

-    /**

-     * Helper method for binding the list activities UI to the tracker data

-     * Tracker data will be sorted in most-recent first order

-     * Will enable automatic UI changes as tracker data changes

-     *

-     * @param layout - layout to populate data

-     */

-    public void bindListUI(int layout) {

-        Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,

-                TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);

-        // Used to map tracker entries from the database to views

-        TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);

-        mActivity.setListAdapter(adapter);

-        cursor.setNotificationUri(mActivity.getContentResolver(),

-                TrackerProvider.CONTENT_URI);

-

-    }

-

-    private class TrackerAdapter extends ResourceCursorAdapter {

-

-        public TrackerAdapter(Context context, int layout, Cursor c) {

-            super(context, layout, c);

-        }

-

-        @Override

-        public void bindView(View view, Context context, Cursor cursor) {

-            final TextView v = (TextView) view

-                    .findViewById(R.id.entrylist_item);

-            String rowText = mFormatter.getOutput(TrackerEntry

-                    .createEntry(cursor));

-            v.setText(rowText);

-        }

-    }

-}

+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.android.locationtracker.data;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+
+import com.android.locationtracker.R;
+
+/**
+ * Used to bind Tracker data to a list view UI
+ */
+public class TrackerListHelper extends TrackerDataHelper {
+
+    private ListActivity mActivity;
+
+    // sort entries by most recent first
+    private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";
+
+    public TrackerListHelper(ListActivity activity) {
+        super(activity, TrackerDataHelper.CSV_FORMATTER);
+        mActivity = activity;
+    }
+
+    /**
+     * Helper method for binding the list activities UI to the tracker data
+     * Tracker data will be sorted in most-recent first order
+     * Will enable automatic UI changes as tracker data changes
+     *
+     * @param layout - layout to populate data
+     */
+    public void bindListUI(int layout) {
+        Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,
+                TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);
+        // Used to map tracker entries from the database to views
+        TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);
+        mActivity.setListAdapter(adapter);
+        cursor.setNotificationUri(mActivity.getContentResolver(),
+                TrackerProvider.CONTENT_URI);
+
+    }
+
+    private class TrackerAdapter extends ResourceCursorAdapter {
+
+        public TrackerAdapter(Context context, int layout, Cursor c) {
+            super(context, layout, c);
+        }
+
+        @Override
+        public void bindView(View view, Context context, Cursor cursor) {
+            final TextView v = (TextView) view
+                    .findViewById(R.id.entrylist_item);
+            String rowText = mFormatter.getOutput(TrackerEntry
+                    .createEntry(cursor));
+            v.setText(rowText);
+        }
+    }
+}
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
index ad02d2b..c0583ce 100644
--- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@
 import java.net.InetAddress;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Random;
 import java.util.UUID;
 
@@ -53,7 +55,7 @@
     static final int MSG_GENERIC_TRIGGER = 4;
 
     private Random random = new Random();
-    private ArrayList<UUID> loadedModelUuids;
+    private HashSet<UUID> loadedModelUuids;
     private ISoundTriggerService soundTriggerService;
     private SoundTriggerManager soundTriggerManager;
 
@@ -68,7 +70,7 @@
         soundTriggerManager = (SoundTriggerManager) context.getSystemService(
                 Context.SOUND_TRIGGER_SERVICE);
 
-        loadedModelUuids = new ArrayList<UUID>();
+        loadedModelUuids = new HashSet<UUID>();
     }
 
     @Override
@@ -170,6 +172,101 @@
         verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
     }
 
+    /**
+     * Tests a more complicated pattern of loading, unloading, triggering, starting and stopping
+     * recognition. Intended to find unexpected errors that occur in unexpected states.
+     */
+    @LargeTest
+    public void testFuzzGenericSoundModel() throws Exception {
+        int numModels = 2;
+
+        final int STATUS_UNLOADED = 0;
+        final int STATUS_LOADED = 1;
+        final int STATUS_STARTED = 2;
+
+        class ModelInfo {
+            int status;
+            GenericSoundModel model;
+
+            public ModelInfo(GenericSoundModel model, int status) {
+                this.status = status;
+                this.model = model;
+            }
+        }
+
+        Random predictableRandom = new Random(100);
+
+        ArrayList modelInfos = new ArrayList<ModelInfo>();
+        for(int i=0; i<numModels; i++) {
+            // Create sound model
+            byte[] data = new byte[1024];
+            predictableRandom.nextBytes(data);
+            UUID modelUuid = UUID.randomUUID();
+            UUID mVendorUuid = UUID.randomUUID();
+            GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+            ModelInfo modelInfo = new ModelInfo(model, STATUS_UNLOADED);
+            modelInfos.add(modelInfo);
+        }
+
+        boolean captureTriggerAudio = true;
+        boolean allowMultipleTriggers = true;
+        RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+                null, null);
+        TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback());
+
+
+        int numOperationsToRun = 100;
+        for(int i=0; i<numOperationsToRun; i++) {
+            // Select a random model
+            int modelInfoIndex = predictableRandom.nextInt(modelInfos.size());
+            ModelInfo modelInfo = (ModelInfo) modelInfos.get(modelInfoIndex);
+
+            // Perform a random operation
+            int operation = predictableRandom.nextInt(5);
+
+            if (operation == 0 && modelInfo.status == STATUS_UNLOADED) {
+                // Update and start sound model
+                soundTriggerService.updateSoundModel(modelInfo.model);
+                loadedModelUuids.add(modelInfo.model.uuid);
+                modelInfo.status = STATUS_LOADED;
+            } else if (operation == 1 && modelInfo.status == STATUS_LOADED) {
+                // Start the sound model
+                int r = soundTriggerService.startRecognition(new ParcelUuid(modelInfo.model.uuid),
+                        spyCallback, config);
+                assertEquals("Could Not Start Recognition with code: " + r,
+                        android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+                modelInfo.status = STATUS_STARTED;
+            } else if (operation == 2 && modelInfo.status == STATUS_STARTED) {
+                // Send trigger to stub HAL
+                Socket socket = new Socket(InetAddress.getLocalHost(), 14035);
+                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+                out.writeBytes("trig " + modelInfo.model.uuid + "\r\n");
+                out.flush();
+                socket.close();
+
+                // Verify trigger was received
+                verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any());
+                reset(spyCallback);
+            } else if (operation == 3 && modelInfo.status == STATUS_STARTED) {
+                // Stop recognition
+                int r = soundTriggerService.stopRecognition(new ParcelUuid(modelInfo.model.uuid),
+                        spyCallback);
+                assertEquals("Could Not Stop Recognition with code: " + r,
+                        android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r);
+                modelInfo.status = STATUS_LOADED;
+            } else if (operation == 4 && modelInfo.status != STATUS_UNLOADED) {
+                // Delete sound model
+                soundTriggerService.deleteSoundModel(new ParcelUuid(modelInfo.model.uuid));
+                loadedModelUuids.remove(modelInfo.model.uuid);
+
+                // Confirm it was deleted
+                GenericSoundModel returnedModel =
+                        soundTriggerService.getSoundModel(new ParcelUuid(modelInfo.model.uuid));
+                assertEquals(null, returnedModel);
+                modelInfo.status = STATUS_UNLOADED;
+            }
+        }
+    }
 
     public class TestRecognitionStatusCallback extends IRecognitionStatusCallback.Stub {
         @Override
diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk
index 3d44e33..dd8a4d4 100644
--- a/tests/VectorDrawableTest/Android.mk
+++ b/tests/VectorDrawableTest/Android.mk
@@ -23,6 +23,4 @@
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SDK_VERSION := current
-
 include $(BUILD_PACKAGE)
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index e648897..7b3beb2 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -18,8 +18,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.dynamic" >
 
-    <uses-sdk android:minSdkVersion="21" />
-
     <application
         android:hardwareAccelerated="true"
         android:label="vector"
diff --git a/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml b/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
new file mode 100644
index 0000000..4f05090
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/btn_radio_on_to_off_bundle.xml
@@ -0,0 +1,190 @@
+<?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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+                 xmlns:android="http://schemas.android.com/apk/res/android">
+    <aapt:attr name="android:drawable">
+        <vector
+                android:width="32dp"
+                android:viewportWidth="32"
+                android:height="32dp"
+                android:viewportHeight="32">
+            <group
+                    android:name="btn_radio_to_off_mtrl_0"
+                    android:translateX="16"
+                    android:translateY="16">
+                <group
+                        android:name="ring_outer">
+                    <path
+                            android:name="ring_outer_path"
+                            android:strokeColor="#FF000000"
+                            android:strokeWidth="2"
+                            android:pathData="M 0.0,-9.0 c 4.9705627482,0.0 9.0,4.0294372518 9.0,9.0 c 0.0,4.9705627482 -4.0294372518,9.0 -9.0,9.0 c -4.9705627482,0.0 -9.0,-4.0294372518 -9.0,-9.0 c 0.0,-4.9705627482 4.0294372518,-9.0 9.0,-9.0 Z"/>
+                </group>
+                <group
+                        android:name="dot_group">
+                    <path
+                            android:name="dot_path"
+                            android:pathData="M 0.0,-5.0 c -2.7619934082,0.0 -5.0,2.2380065918 -5.0,5.0 c 0.0,2.7619934082 2.2380065918,5.0 5.0,5.0 c 2.7619934082,0.0 5.0,-2.2380065918 5.0,-5.0 c 0.0,-2.7619934082 -2.2380065918,-5.0 -5.0,-5.0 Z"
+                            android:fillColor="#FF000000"/>
+                </group>
+            </group>
+        </vector>
+    </aapt:attr>
+    <target android:name="ring_outer">
+        <aapt:attr name="android:animation">
+            <set
+                    xmlns:android="http://schemas.android.com/apk/res/android" >
+                <set
+                        android:ordering="sequentially" >
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleX"
+                            android:valueFrom="1.0"
+                            android:valueTo="0.9"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in" />
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleX"
+                            android:valueFrom="0.9"
+                            android:valueTo="0.5"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleX"
+                            android:valueFrom="0.5"
+                            android:valueTo="1.0"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                </set>
+                <set
+                        android:ordering="sequentially" >
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleY"
+                            android:valueFrom="1.0"
+                            android:valueTo="0.9"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in" />
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleY"
+                            android:valueFrom="0.9"
+                            android:valueTo="0.5"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleY"
+                            android:valueFrom="0.5"
+                            android:valueTo="1.0"
+                            android:valueType="floatType"
+                            android:interpolator="@interpolator/btn_radio_to_off_mtrl_animation_interpolator_0" />
+                </set>
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="ring_outer_path">
+        <aapt:attr name="android:animation">
+            <set
+                    xmlns:android="http://schemas.android.com/apk/res/android">
+                <set
+                        android:ordering="sequentially">
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="strokeWidth"
+                            android:valueFrom="2.0"
+                            android:valueTo="2.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="strokeWidth"
+                            android:valueFrom="2.0"
+                            android:valueTo="18.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="strokeWidth"
+                            android:valueFrom="18.0"
+                            android:valueTo="2.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                </set>
+
+            </set>
+        </aapt:attr>
+    </target>
+    <target
+            android:name="dot_group">
+        <aapt:attr name="android:animation">
+            <set
+                    xmlns:android="http://schemas.android.com/apk/res/android">
+                <set
+                        android:ordering="sequentially">
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleX"
+                            android:valueFrom="1.0"
+                            android:valueTo="1.4"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleX"
+                            android:valueFrom="1.4"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleX"
+                            android:valueFrom="0.0"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                </set>
+                <set
+                        android:ordering="sequentially">
+                    <objectAnimator
+                            android:duration="183"
+                            android:propertyName="scaleY"
+                            android:valueFrom="1.0"
+                            android:valueTo="1.4"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="16"
+                            android:propertyName="scaleY"
+                            android:valueFrom="1.4"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                    <objectAnimator
+                            android:duration="300"
+                            android:propertyName="scaleY"
+                            android:valueFrom="0.0"
+                            android:valueTo="0.0"
+                            android:valueType="floatType"
+                            android:interpolator="@android:interpolator/fast_out_slow_in"/>
+                </set>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml b/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
new file mode 100644
index 0000000..d3728c4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.0 0.4,1.0 1.0,1.0" />
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index 9351f63..8f538ae 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -24,11 +24,13 @@
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.ScrollView;
+import android.widget.TextView;
 
 public class AnimatedVectorDrawableTest extends Activity implements View.OnClickListener {
     private static final String LOGCAT = "AnimatedVectorDrawableTest";
 
     protected int[] icon = {
+            R.drawable.btn_radio_on_to_off_bundle,
             R.drawable.ic_rotate_2_portrait_v2_animation,
             R.drawable.ic_signal_airplane_v2_animation,
             R.drawable.ic_hourglass_animation,
@@ -44,35 +46,51 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         final int[] layerTypes = {View.LAYER_TYPE_SOFTWARE, View.LAYER_TYPE_HARDWARE};
+        final boolean[] forceOnUi = {false, true};
         super.onCreate(savedInstanceState);
 
         ScrollView scrollView = new ScrollView(this);
         GridLayout container = new GridLayout(this);
         scrollView.addView(container);
-        container.setColumnCount(2);
+        container.setColumnCount(layerTypes.length * forceOnUi.length);
 
+        for (int j = 0; j < layerTypes.length; j++) {
+            for (int k = 0; k < forceOnUi.length; k++) {
+                TextView textView = new TextView(this);
+                String category = "Layer:"
+                        + (layerTypes[j] == View.LAYER_TYPE_SOFTWARE ? "SW" : "HW")
+                        + (forceOnUi[k] == true ? ",forceUI" : "");
+                textView.setText(category);
+                container.addView(textView);
+            }
+        }
         for (int i = 0; i < icon.length; i++) {
             for (int j = 0; j < layerTypes.length; j++) {
-                Button button = new Button(this);
-                button.setWidth(400);
-                button.setHeight(400);
-                button.setLayerType(layerTypes[j], null);
-                button.setBackgroundResource(icon[i]);
-                AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
-                d.registerAnimationCallback(new Animatable2.AnimationCallback() {
-                    @Override
-                    public void onAnimationStart(Drawable drawable) {
-                        Log.v(LOGCAT, "Animator start");
+                for (int k = 0; k < forceOnUi.length; k++) {
+                    Button button = new Button(this);
+                    button.setWidth(300);
+                    button.setHeight(300);
+                    button.setLayerType(layerTypes[j], null);
+                    button.setBackgroundResource(icon[i]);
+                    AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
+                    if (forceOnUi[k] == true) {
+                        d.forceAnimationOnUI();
                     }
+                    d.registerAnimationCallback(new Animatable2.AnimationCallback() {
+                        @Override
+                        public void onAnimationStart(Drawable drawable) {
+                            Log.v(LOGCAT, "Animator start");
+                        }
 
-                    @Override
-                    public void onAnimationEnd(Drawable drawable) {
-                        Log.v(LOGCAT, "Animator end");
-                    }
-                });
+                        @Override
+                        public void onAnimationEnd(Drawable drawable) {
+                            Log.v(LOGCAT, "Animator end");
+                        }
+                    });
 
-                container.addView(button);
-                button.setOnClickListener(this);
+                    container.addView(button);
+                    button.setOnClickListener(this);
+                }
             }
         }
 
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index cbd8480..c1cfd0b 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -388,10 +388,6 @@
 
     if (script[0]) {
         memcpy(out->localeScript, script, sizeof(out->localeScript));
-        out->localeScriptWasComputed = false;
-    } else {
-        out->computeScript();
-        out->localeScriptWasComputed = true;
     }
 
     if (variant[0]) {
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 641c34b..d631f35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -33,7 +33,7 @@
     ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
     ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
     ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
-    ".amr", ".awb", ".wma", ".wmv", ".webm"
+    ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"
 };
 
 /* fwd decls, so I can write this downward */
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 85d22ff..876a422 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -54,6 +54,7 @@
 	Debug.cpp \
 	Flags.cpp \
 	java/AnnotationProcessor.cpp \
+	java/ClassDefinition.cpp \
 	java/JavaClassGenerator.cpp \
 	java/ManifestClassGenerator.cpp \
 	java/ProguardRules.cpp \
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 12f56fc..be57661 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -268,10 +268,6 @@
 
     if (script[0]) {
         memcpy(out->localeScript, script, sizeof(out->localeScript));
-        out->localeScriptWasComputed = false;
-    } else {
-        out->computeScript();
-        out->localeScriptWasComputed = true;
     }
 
     if (variant[0]) {
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
index d59dc60..0b7129a 100644
--- a/tools/aapt2/integration-tests/StaticLibOne/Android.mk
+++ b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
@@ -22,4 +22,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+# We need this to compile the Java sources of AaptTestStaticLibTwo using javac.
+LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 496e92e..ba74439 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -64,7 +64,7 @@
     mComment << "\n *";
 }
 
-void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) {
+void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) const {
     if (mHasComments) {
         std::string result = mComment.str();
         for (StringPiece line : util::tokenize<char>(result, '\n')) {
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index fadf584..0fc5b08 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -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);
+    void writeToStream(std::ostream* out, const StringPiece& prefix) const;
 
 private:
     enum : uint32_t {
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
new file mode 100644
index 0000000..08f2c8b
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "java/ClassDefinition.h"
+#include "util/StringPiece.h"
+
+#include <ostream>
+
+namespace aapt {
+
+bool ClassDefinition::empty() const {
+    for (const std::unique_ptr<ClassMember>& member : mMembers) {
+        if (!member->empty()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void ClassDefinition::writeToStream(const StringPiece& prefix, bool final,
+                                    std::ostream* out) const {
+    if (mMembers.empty() && !mCreateIfEmpty) {
+        return;
+    }
+
+    ClassMember::writeToStream(prefix, final, out);
+
+    *out << prefix << "public ";
+    if (mQualifier == ClassQualifier::Static) {
+        *out << "static ";
+    }
+    *out << "final class " << mName << " {\n";
+
+    std::string newPrefix = prefix.toString();
+    newPrefix.append(kIndent);
+
+    for (const std::unique_ptr<ClassMember>& member : mMembers) {
+        member->writeToStream(newPrefix, final, out);
+        *out << "\n";
+    }
+
+    *out << prefix << "}";
+}
+
+constexpr static const char* sWarningHeader =
+        "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+        " *\n"
+        " * This class was automatically generated by the\n"
+        " * aapt tool from the resource data it found. It\n"
+        " * should not be modified by hand.\n"
+        " */\n\n";
+
+bool ClassDefinition::writeJavaFile(const ClassDefinition* def,
+                                    const StringPiece& package,
+                                    bool final,
+                                    std::ostream* out) {
+    *out << sWarningHeader << "package " << package << ";\n\n";
+    def->writeToStream("", final, out);
+    return bool(*out);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
new file mode 100644
index 0000000..53e0f6f
--- /dev/null
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_JAVA_CLASSDEFINITION_H
+#define AAPT_JAVA_CLASSDEFINITION_H
+
+#include "Resource.h"
+#include "java/AnnotationProcessor.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <android-base/macros.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+// The number of attributes to emit per line in a Styleable array.
+constexpr static size_t kAttribsPerLine = 4;
+constexpr static const char* kIndent = "  ";
+
+class ClassMember {
+public:
+    virtual ~ClassMember() = default;
+
+    AnnotationProcessor* getCommentBuilder() {
+        return &mProcessor;
+    }
+
+    virtual bool empty() const = 0;
+
+    virtual void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
+        mProcessor.writeToStream(out, prefix);
+    }
+
+private:
+    AnnotationProcessor mProcessor;
+};
+
+template <typename T>
+class PrimitiveMember : public ClassMember {
+public:
+    PrimitiveMember(const StringPiece& name, const T& val) :
+            mName(name.toString()), mVal(val) {
+    }
+
+    bool empty() const override {
+        return false;
+    }
+
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+        ClassMember::writeToStream(prefix, final, out);
+
+        *out << prefix << "public static " << (final ? "final " : "")
+             << "int " << mName << "=" << mVal << ";";
+    }
+
+private:
+    std::string mName;
+    T mVal;
+
+    DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+/**
+ * Specialization for strings so they get the right type and are quoted with "".
+ */
+template <>
+class PrimitiveMember<std::string> : public ClassMember {
+public:
+    PrimitiveMember(const StringPiece& name, const std::string& val) :
+            mName(name.toString()), mVal(val) {
+    }
+
+    bool empty() const override {
+        return false;
+    }
+
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+        ClassMember::writeToStream(prefix, final, out);
+
+        *out << prefix << "public static " << (final ? "final " : "")
+             << "String " << mName << "=\"" << mVal << "\";";
+    }
+
+private:
+    std::string mName;
+    std::string mVal;
+
+    DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+};
+
+using IntMember = PrimitiveMember<uint32_t>;
+using ResourceMember = PrimitiveMember<ResourceId>;
+using StringMember = PrimitiveMember<std::string>;
+
+template <typename T>
+class PrimitiveArrayMember : public ClassMember {
+public:
+    PrimitiveArrayMember(const StringPiece& name) :
+            mName(name.toString()) {
+    }
+
+    void addElement(const T& val) {
+        mElements.push_back(val);
+    }
+
+    bool empty() const override {
+        return false;
+    }
+
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override {
+        ClassMember::writeToStream(prefix, final, out);
+
+        *out << "public static final int[] " << mName << "={";
+
+        const auto begin = mElements.begin();
+        const auto end = mElements.end();
+        for (auto current = begin; current != end; ++current) {
+            if (std::distance(begin, current) % kAttribsPerLine == 0) {
+                *out << "\n" << prefix << kIndent << kIndent;
+            }
+
+            *out << *current;
+            if (std::distance(current, end) > 1) {
+                *out << ", ";
+            }
+        }
+        *out << "\n" << prefix << kIndent <<"};";
+    }
+
+private:
+    std::string mName;
+    std::vector<T> mElements;
+
+    DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+};
+
+using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
+
+enum class ClassQualifier {
+    None,
+    Static
+};
+
+class ClassDefinition : public ClassMember {
+public:
+    static bool writeJavaFile(const ClassDefinition* def,
+                              const StringPiece& package,
+                              bool final,
+                              std::ostream* out);
+
+    ClassDefinition(const StringPiece& name, ClassQualifier qualifier, bool createIfEmpty) :
+            mName(name.toString()), mQualifier(qualifier), mCreateIfEmpty(createIfEmpty) {
+    }
+
+    void addMember(std::unique_ptr<ClassMember> member) {
+        mMembers.push_back(std::move(member));
+    }
+
+    bool empty() const override;
+    void writeToStream(const StringPiece& prefix, bool final, std::ostream* out) const override;
+
+private:
+    std::string mName;
+    ClassQualifier mQualifier;
+    bool mCreateIfEmpty;
+    std::vector<std::unique_ptr<ClassMember>> mMembers;
+
+    DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+};
+
+} // namespace aapt
+
+#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/ClassDefinitionWriter.h b/tools/aapt2/java/ClassDefinitionWriter.h
deleted file mode 100644
index cf92c9a..0000000
--- a/tools/aapt2/java/ClassDefinitionWriter.h
+++ /dev/null
@@ -1,142 +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.
- */
-
-#ifndef AAPT_JAVA_CLASSDEFINITION_H
-#define AAPT_JAVA_CLASSDEFINITION_H
-
-#include "Resource.h"
-#include "java/AnnotationProcessor.h"
-#include "util/StringPiece.h"
-#include "util/Util.h"
-
-#include <sstream>
-#include <string>
-
-namespace aapt {
-
-struct ClassDefinitionWriterOptions {
-    bool useFinalQualifier = false;
-    bool forceCreationIfEmpty = false;
-};
-
-/**
- * Writes a class for use in R.java or Manifest.java.
- */
-class ClassDefinitionWriter {
-public:
-    ClassDefinitionWriter(const StringPiece& name, const ClassDefinitionWriterOptions& options) :
-            mName(name.toString()), mOptions(options), mStarted(false) {
-    }
-
-    ClassDefinitionWriter(const StringPiece16& name, const ClassDefinitionWriterOptions& options) :
-            mName(util::utf16ToUtf8(name)), mOptions(options), mStarted(false) {
-    }
-
-    void addIntMember(const StringPiece& name, AnnotationProcessor* processor,
-                      const uint32_t val) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
-             << "int " << name << "=" << val << ";\n";
-    }
-
-    void addStringMember(const StringPiece16& name, AnnotationProcessor* processor,
-                         const StringPiece16& val) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
-             << "String " << name << "=\"" << val << "\";\n";
-    }
-
-    void addResourceMember(const StringPiece& name, AnnotationProcessor* processor,
-                           const ResourceId id) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static " << (mOptions.useFinalQualifier ? "final " : "")
-             << "int " << name << "=" << id <<";\n";
-    }
-
-    template <typename Iterator, typename FieldAccessorFunc>
-    void addArrayMember(const StringPiece& name, AnnotationProcessor* processor,
-                        const Iterator begin, const Iterator end, FieldAccessorFunc f) {
-        ensureClassDeclaration();
-        if (processor) {
-            processor->writeToStream(&mOut, kIndent);
-        }
-        mOut << kIndent << "public static final int[] " << name << "={";
-
-        for (Iterator current = begin; current != end; ++current) {
-            if (std::distance(begin, current) % kAttribsPerLine == 0) {
-                mOut << "\n" << kIndent << kIndent;
-            }
-
-            mOut << f(*current);
-            if (std::distance(current, end) > 1) {
-                mOut << ", ";
-            }
-        }
-        mOut << "\n" << kIndent <<"};\n";
-    }
-
-    void writeToStream(std::ostream* out, const StringPiece& prefix,
-                       AnnotationProcessor* processor=nullptr) {
-        if (mOptions.forceCreationIfEmpty) {
-            ensureClassDeclaration();
-        }
-
-        if (!mStarted) {
-            return;
-        }
-
-        if (processor) {
-            processor->writeToStream(out, prefix);
-        }
-
-        std::string result = mOut.str();
-        for (StringPiece line : util::tokenize<char>(result, '\n')) {
-            *out << prefix << line << "\n";
-        }
-        *out << prefix << "}\n";
-    }
-
-private:
-    constexpr static const char* kIndent = "  ";
-
-    // The number of attributes to emit per line in a Styleable array.
-    constexpr static size_t kAttribsPerLine = 4;
-
-    void ensureClassDeclaration() {
-        if (!mStarted) {
-            mStarted = true;
-            mOut << "public static final class " << mName << " {\n";
-        }
-    }
-
-    std::stringstream mOut;
-    std::string mName;
-    ClassDefinitionWriterOptions mOptions;
-    bool mStarted;
-};
-
-} // namespace aapt
-
-#endif /* AAPT_JAVA_CLASSDEFINITION_H */
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 01330dc..092bab24 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -21,7 +21,7 @@
 #include "ValueVisitor.h"
 
 #include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
 #include "java/JavaClassGenerator.h"
 #include "process/SymbolTable.h"
 #include "util/StringPiece.h"
@@ -39,16 +39,6 @@
         mContext(context), mTable(table), mOptions(options) {
 }
 
-static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) {
-    *out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
-            " *\n"
-            " * This class was automatically generated by the\n"
-            " * aapt tool from the resource data it found. It\n"
-            " * should not be modified by hand.\n"
-            " */\n\n"
-            "package " << packageNameToGenerate << ";\n\n";
-}
-
 static const std::set<StringPiece16> sJavaIdentifiers = {
     u"abstract", u"assert", u"boolean", u"break", u"byte",
     u"case", u"catch", u"char", u"class", u"const", u"continue",
@@ -110,15 +100,15 @@
     if (typeMask & android::ResTable_map::TYPE_REFERENCE) {
         processor->appendComment(
                 "<p>May be a reference to another resource, in the form\n"
-                        "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
-                        "attribute in the form\n"
-                        "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
+                "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n"
+                "attribute in the form\n"
+                "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\".");
     }
 
     if (typeMask & android::ResTable_map::TYPE_STRING) {
         processor->appendComment(
                 "<p>May be a string value, using '\\\\;' to escape characters such as\n"
-                        "'\\\\n' or '\\\\uxxxx' for a unicode character;");
+                "'\\\\n' or '\\\\uxxxx' for a unicode character;");
     }
 
     if (typeMask & android::ResTable_map::TYPE_INTEGER) {
@@ -128,14 +118,14 @@
     if (typeMask & android::ResTable_map::TYPE_BOOLEAN) {
         processor->appendComment(
                 "<p>May be a boolean value, such as \"<code>true</code>\" or\n"
-                        "\"<code>false</code>\".");
+                "\"<code>false</code>\".");
     }
 
     if (typeMask & android::ResTable_map::TYPE_COLOR) {
         processor->appendComment(
                 "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n"
-                        "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
-                        "\"<code>#<i>aarrggbb</i></code>\".");
+                "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n"
+                "\"<code>#<i>aarrggbb</i></code>\".");
     }
 
     if (typeMask & android::ResTable_map::TYPE_FLOAT) {
@@ -146,33 +136,33 @@
     if (typeMask & android::ResTable_map::TYPE_DIMENSION) {
         processor->appendComment(
                 "<p>May be a dimension value, which is a floating point number appended with a\n"
-                        "unit such as \"<code>14.5sp</code>\".\n"
-                        "Available units are: px (pixels), dp (density-independent pixels),\n"
-                        "sp (scaled pixels based on preferred font size), in (inches), and\n"
-                        "mm (millimeters).");
+                "unit such as \"<code>14.5sp</code>\".\n"
+                "Available units are: px (pixels), dp (density-independent pixels),\n"
+                "sp (scaled pixels based on preferred font size), in (inches), and\n"
+                "mm (millimeters).");
     }
 
     if (typeMask & android::ResTable_map::TYPE_FRACTION) {
         processor->appendComment(
                 "<p>May be a fractional value, which is a floating point number appended with\n"
-                        "either % or %p, such as \"<code>14.5%</code>\".\n"
-                        "The % suffix always means a percentage of the base size;\n"
-                        "the optional %p suffix provides a size relative to some parent container.");
+                "either % or %p, such as \"<code>14.5%</code>\".\n"
+                "The % suffix always means a percentage of the base size;\n"
+                "the optional %p suffix provides a size relative to some parent container.");
     }
 
     if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) {
         if (typeMask & android::ResTable_map::TYPE_FLAGS) {
             processor->appendComment(
                     "<p>Must be one or more (separated by '|') of the following "
-                            "constant values.</p>");
+                    "constant values.</p>");
         } else {
             processor->appendComment("<p>Must be one of the following constant values.</p>");
         }
 
         processor->appendComment("<table>\n<colgroup align=\"left\" />\n"
-                                         "<colgroup align=\"left\" />\n"
-                                         "<colgroup align=\"left\" />\n"
-                                         "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
+                                 "<colgroup align=\"left\" />\n"
+                                 "<colgroup align=\"left\" />\n"
+                                 "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n");
         for (const Attribute::Symbol& symbol : attr->symbols) {
             std::stringstream line;
             line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>"
@@ -214,13 +204,15 @@
     }
 }
 
-void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
-                                                     AnnotationProcessor* processor,
-                                                     const StringPiece16& packageNameToGenerate,
-                                                     const std::u16string& entryName,
-                                                     const Styleable* styleable) {
+void JavaClassGenerator::addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+                                                    const std::u16string& entryName,
+                                                    const Styleable* styleable,
+                                                    ClassDefinition* outStyleableClassDef) {
     const std::string className = transform(entryName);
 
+    std::unique_ptr<ResourceArrayMember> styleableArrayDef =
+            util::make_unique<ResourceArrayMember>(className);
+
     // This must be sorted by resource ID.
     std::vector<StyleableAttr> sortedAttributes;
     sortedAttributes.reserve(styleable->entries.size());
@@ -230,6 +222,8 @@
         assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry");
         assert(attr.name && "no name set for Styleable entry");
 
+        // We will need the unmangled, transformed name in the comments and the field,
+        // so create it once and cache it in this StyleableAttr data structure.
         StyleableAttr styleableAttr = {};
         styleableAttr.attrRef = &attr;
         styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className,
@@ -247,6 +241,8 @@
             mangledReference.name = mangledName;
         }
 
+        // Look up the symbol so that we can write out in the comments what are possible
+        // legal values for this attribute.
         const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference(
                 mangledReference);
         if (symbol) {
@@ -254,10 +250,11 @@
         }
         sortedAttributes.push_back(std::move(styleableAttr));
     }
+
+    // Sort the attributes by ID.
     std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr);
 
     const size_t attrCount = sortedAttributes.size();
-
     if (attrCount > 0) {
         // Build the comment string for the Styleable. It includes details about the
         // child attributes.
@@ -267,6 +264,7 @@
         } else {
             styleableComment << "Attributes that can be used with a " << className << ".\n";
         }
+
         styleableComment <<
                 "<p>Includes the following attributes:</p>\n"
                 "<table>\n"
@@ -274,7 +272,7 @@
                 "<colgroup align=\"left\" />\n"
                 "<tr><th>Attribute</th><th>Description</th></tr>\n";
 
-        for (const auto& entry : sortedAttributes) {
+        for (const StyleableAttr& entry : sortedAttributes) {
             const ResourceName& attrName = entry.attrRef->name.value();
             styleableComment << "<tr><td>";
             styleableComment << "<code>{@link #"
@@ -292,21 +290,22 @@
             styleableComment << "</td></tr>\n";
         }
         styleableComment << "</table>\n";
-        for (const auto& entry : sortedAttributes) {
+
+        for (const StyleableAttr& entry : sortedAttributes) {
             styleableComment << "@see #" << entry.fieldName << "\n";
         }
-        processor->appendComment(styleableComment.str());
+
+        styleableArrayDef->getCommentBuilder()->appendComment(styleableComment.str());
     }
 
-    auto accessorFunc = [](const StyleableAttr& a) -> ResourceId {
-        return a.attrRef->id ? a.attrRef->id.value() : ResourceId(0);
-    };
+    // Add the ResourceIds to the array member.
+    for (const StyleableAttr& styleableAttr : sortedAttributes) {
+        styleableArrayDef->addElement(
+                styleableAttr.attrRef->id ? styleableAttr.attrRef->id.value() : ResourceId(0));
+    }
 
-    // First we emit the array containing the IDs of each attribute.
-    outClassDef->addArrayMember(className, processor,
-                                sortedAttributes.begin(),
-                                sortedAttributes.end(),
-                                accessorFunc);
+    // Add the Styleable array to the Styleable class.
+    outStyleableClassDef->addMember(std::move(styleableArrayDef));
 
     // Now we emit the indices into the array.
     for (size_t i = 0; i < attrCount; i++) {
@@ -318,7 +317,10 @@
             packageName = mContext->getCompilationPackage();
         }
 
-        AnnotationProcessor attrProcessor;
+        std::unique_ptr<IntMember> indexMember = util::make_unique<IntMember>(
+                sortedAttributes[i].fieldName, i);
+
+        AnnotationProcessor* attrProcessor = indexMember->getCommentBuilder();
 
         StringPiece16 comment = styleableAttr.attrRef->getComment();
         if (styleableAttr.attribute && comment.empty()) {
@@ -326,8 +328,8 @@
         }
 
         if (!comment.empty()) {
-            attrProcessor.appendComment("<p>\n@attr description");
-            attrProcessor.appendComment(comment);
+            attrProcessor->appendComment("<p>\n@attr description");
+            attrProcessor->appendComment(comment);
         } else {
             std::stringstream defaultComment;
             defaultComment
@@ -335,27 +337,29 @@
                     << "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n"
                     << "attribute's value can be found in the "
                     << "{@link #" << className << "} array.";
-            attrProcessor.appendComment(defaultComment.str());
+            attrProcessor->appendComment(defaultComment.str());
         }
 
-        attrProcessor.appendNewLine();
+        attrProcessor->appendNewLine();
 
         if (styleableAttr.attribute) {
-            addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get());
-            attrProcessor.appendNewLine();
+            addAttributeFormatDoc(attrProcessor, styleableAttr.attribute.get());
+            attrProcessor->appendNewLine();
         }
 
         std::stringstream doclavaName;
         doclavaName << "@attr name " << packageName << ":" << attrName.entry;;
-        attrProcessor.appendComment(doclavaName.str());
-        outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i);
+        attrProcessor->appendComment(doclavaName.str());
+
+        outStyleableClassDef->addMember(std::move(indexMember));
     }
 }
 
-bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef,
-                                              const StringPiece16& packageNameToGenerate,
-                                              const ResourceTablePackage* package,
-                                              const ResourceTableType* type) {
+bool JavaClassGenerator::addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+                                               const ResourceTablePackage* package,
+                                               const ResourceTableType* type,
+                                               ClassDefinition* outTypeClassDef) {
+
     for (const auto& entry : type->entries) {
         if (skipSymbol(entry->symbolStatus.state)) {
             continue;
@@ -389,33 +393,41 @@
             return false;
         }
 
-        // Build the comments and annotations for this entry.
-
-        AnnotationProcessor processor;
-        if (entry->symbolStatus.state != SymbolState::kUndefined) {
-            processor.appendComment(entry->symbolStatus.comment);
-        }
-
-        for (const auto& configValue : entry->values) {
-            processor.appendComment(configValue->value->getComment());
-        }
-
-        // If this is an Attribute, append the format Javadoc.
-        if (!entry->values.empty()) {
-            if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
-                // We list out the available values for the given attribute.
-                addAttributeFormatDoc(&processor, attr);
-            }
-        }
-
         if (type->type == ResourceType::kStyleable) {
             assert(!entry->values.empty());
+
             const Styleable* styleable = static_cast<const Styleable*>(
                     entry->values.front()->value.get());
-            writeStyleableEntryForClass(outClassDef, &processor, packageNameToGenerate,
-                                        unmangledName, styleable);
+
+            // Comments are handled within this method.
+            addMembersToStyleableClass(packageNameToGenerate, unmangledName, styleable,
+                                       outTypeClassDef);
         } else {
-            outClassDef->addResourceMember(transform(unmangledName), &processor, id);
+            std::unique_ptr<ResourceMember> resourceMember =
+                    util::make_unique<ResourceMember>(transform(unmangledName), id);
+
+            // Build the comments and annotations for this entry.
+            AnnotationProcessor* processor = resourceMember->getCommentBuilder();
+
+            // Add the comments from any <public> tags.
+            if (entry->symbolStatus.state != SymbolState::kUndefined) {
+                processor->appendComment(entry->symbolStatus.comment);
+            }
+
+            // Add the comments from all configurations of this entry.
+            for (const auto& configValue : entry->values) {
+                processor->appendComment(configValue->value->getComment());
+            }
+
+            // If this is an Attribute, append the format Javadoc.
+            if (!entry->values.empty()) {
+                if (Attribute* attr = valueCast<Attribute>(entry->values.front()->value.get())) {
+                    // We list out the available values for the given attribute.
+                    addAttributeFormatDoc(processor, attr);
+                }
+            }
+
+            outTypeClassDef->addMember(std::move(resourceMember));
         }
     }
     return true;
@@ -425,11 +437,19 @@
     return generate(packageNameToGenerate, packageNameToGenerate, out);
 }
 
+static void appendJavaDocAnnotations(const std::vector<std::string>& annotations,
+                                     AnnotationProcessor* processor) {
+    for (const std::string& annotation : annotations) {
+        std::string properAnnotation = "@";
+        properAnnotation += annotation;
+        processor->appendComment(properAnnotation);
+    }
+}
+
 bool JavaClassGenerator::generate(const StringPiece16& packageNameToGenerate,
                                   const StringPiece16& outPackageName, std::ostream* out) {
-    generateHeader(outPackageName, out);
 
-    *out << "public final class R {\n";
+    ClassDefinition rClass("R", ClassQualifier::None, true);
 
     for (const auto& package : mTable->packages) {
         for (const auto& type : package->types) {
@@ -437,13 +457,15 @@
                 continue;
             }
 
-            ClassDefinitionWriterOptions classOptions;
-            classOptions.useFinalQualifier = mOptions.useFinal;
-            classOptions.forceCreationIfEmpty =
+            const bool forceCreationIfEmpty =
                     (mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
-            ClassDefinitionWriter classDef(toString(type->type), classOptions);
-            bool result = writeEntriesForClass(&classDef, packageNameToGenerate,
-                                               package.get(), type.get());
+
+            std::unique_ptr<ClassDefinition> classDef = util::make_unique<ClassDefinition>(
+                    util::utf16ToUtf8(toString(type->type)), ClassQualifier::Static,
+                    forceCreationIfEmpty);
+
+            bool result = addMembersToTypeClass(packageNameToGenerate, package.get(), type.get(),
+                                                classDef.get());
             if (!result) {
                 return false;
             }
@@ -452,30 +474,36 @@
                 // Also include private attributes in this same class.
                 ResourceTableType* privType = package->findType(ResourceType::kAttrPrivate);
                 if (privType) {
-                    result = writeEntriesForClass(&classDef, packageNameToGenerate,
-                                                  package.get(), privType);
+                    result = addMembersToTypeClass(packageNameToGenerate, package.get(), privType,
+                                                   classDef.get());
                     if (!result) {
                         return false;
                     }
                 }
             }
 
-            AnnotationProcessor processor;
             if (type->type == ResourceType::kStyleable &&
                     mOptions.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) {
                 // When generating a public R class, we don't want Styleable to be part of the API.
                 // It is only emitted for documentation purposes.
-                processor.appendComment("@doconly");
+                classDef->getCommentBuilder()->appendComment("@doconly");
             }
-            classDef.writeToStream(out, "  ", &processor);
+
+            appendJavaDocAnnotations(mOptions.javadocAnnotations, classDef->getCommentBuilder());
+
+            rClass.addMember(std::move(classDef));
         }
     }
 
-    *out << "}\n";
+    appendJavaDocAnnotations(mOptions.javadocAnnotations, rClass.getCommentBuilder());
+
+    if (!ClassDefinition::writeJavaFile(&rClass, util::utf16ToUtf8(outPackageName),
+                                        mOptions.useFinal, out)) {
+        return false;
+    }
+
     out->flush();
     return true;
 }
 
-
-
 } // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 7e46f8c..77e0ed7 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -28,7 +28,7 @@
 namespace aapt {
 
 class AnnotationProcessor;
-class ClassDefinitionWriter;
+class ClassDefinition;
 
 struct JavaClassGeneratorOptions {
     /*
@@ -44,6 +44,11 @@
     };
 
     SymbolTypes types = SymbolTypes::kAll;
+
+    /**
+     * A list of JavaDoc annotations to add to the comments of all generated classes.
+     */
+    std::vector<std::string> javadocAnnotations;
 };
 
 /*
@@ -70,16 +75,15 @@
     const std::string& getError() const;
 
 private:
-    bool writeEntriesForClass(ClassDefinitionWriter* outClassDef,
-                              const StringPiece16& packageNameToGenerate,
-                              const ResourceTablePackage* package,
-                              const ResourceTableType* type);
+    bool addMembersToTypeClass(const StringPiece16& packageNameToGenerate,
+                               const ResourceTablePackage* package,
+                               const ResourceTableType* type,
+                               ClassDefinition* outTypeClassDef);
 
-    void writeStyleableEntryForClass(ClassDefinitionWriter* outClassDef,
-                                     AnnotationProcessor* processor,
-                                     const StringPiece16& packageNameToGenerate,
-                                     const std::u16string& entryName,
-                                     const Styleable* styleable);
+    void addMembersToStyleableClass(const StringPiece16& packageNameToGenerate,
+                                    const std::u16string& entryName,
+                                    const Styleable* styleable,
+                                    ClassDefinition* outStyleableClassDef);
 
     bool skipSymbol(SymbolState state);
 
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a9b4c14..be8955e 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -16,7 +16,7 @@
 
 #include "Source.h"
 #include "java/AnnotationProcessor.h"
-#include "java/ClassDefinitionWriter.h"
+#include "java/ClassDefinition.h"
 #include "java/ManifestClassGenerator.h"
 #include "util/Maybe.h"
 #include "xml/XmlDom.h"
@@ -58,8 +58,8 @@
     return result;
 }
 
-static bool writeSymbol(IDiagnostics* diag, ClassDefinitionWriter* outClassDef, const Source& source,
-                        xml::Element* el) {
+static bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
+                        ClassDefinition* classDef) {
     xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
     if (!attr) {
         diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
@@ -72,54 +72,53 @@
         return false;
     }
 
-    AnnotationProcessor processor;
-    processor.appendComment(el->comment);
-    outClassDef->addStringMember(result.value(), &processor, attr->value);
+    std::unique_ptr<StringMember> stringMember = util::make_unique<StringMember>(
+            util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
+    stringMember->getCommentBuilder()->appendComment(el->comment);
+
+    classDef->addMember(std::move(stringMember));
     return true;
 }
 
-bool ManifestClassGenerator::generate(IDiagnostics* diag, const StringPiece16& package,
-                                      xml::XmlResource* res, std::ostream* out) {
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
     xml::Element* el = xml::findRootElement(res->root.get());
     if (!el) {
-        return false;
+        diag->error(DiagMessage(res->file.source) << "no root tag defined");
+        return {};
     }
 
     if (el->name != u"manifest" && !el->namespaceUri.empty()) {
         diag->error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
-        return false;
+        return {};
     }
 
-    *out << "package " << package << ";\n\n"
-         << "public final class Manifest {\n";
+    std::unique_ptr<ClassDefinition> permissionClass =
+            util::make_unique<ClassDefinition>("permission", ClassQualifier::Static, false);
+    std::unique_ptr<ClassDefinition> permissionGroupClass =
+            util::make_unique<ClassDefinition>("permission_group", ClassQualifier::Static, false);
 
     bool error = false;
+
     std::vector<xml::Element*> children = el->getChildElements();
-
-    ClassDefinitionWriterOptions classOptions;
-    classOptions.useFinalQualifier = true;
-    classOptions.forceCreationIfEmpty = false;
-
-    // First write out permissions.
-    ClassDefinitionWriter classDef("permission", classOptions);
     for (xml::Element* childEl : children) {
-        if (childEl->namespaceUri.empty() && childEl->name == u"permission") {
-            error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
+        if (childEl->namespaceUri.empty()) {
+            if (childEl->name == u"permission") {
+                error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
+            } else if (childEl->name == u"permission-group") {
+                error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
+            }
         }
     }
-    classDef.writeToStream(out, "  ");
 
-    // Next write out permission groups.
-    classDef = ClassDefinitionWriter("permission_group", classOptions);
-    for (xml::Element* childEl : children) {
-        if (childEl->namespaceUri.empty() && childEl->name == u"permission-group") {
-            error |= !writeSymbol(diag, &classDef, res->file.source, childEl);
-        }
+    if (error) {
+        return {};
     }
-    classDef.writeToStream(out, "  ");
 
-    *out << "}\n";
-    return !error;
+    std::unique_ptr<ClassDefinition> manifestClass =
+            util::make_unique<ClassDefinition>("Manifest", ClassQualifier::None, false);
+    manifestClass->addMember(std::move(permissionClass));
+    manifestClass->addMember(std::move(permissionGroupClass));
+    return manifestClass;
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 226ed23..f565289 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -18,6 +18,7 @@
 #define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
 
 #include "Diagnostics.h"
+#include "java/ClassDefinition.h"
 #include "util/StringPiece.h"
 #include "xml/XmlDom.h"
 
@@ -25,10 +26,7 @@
 
 namespace aapt {
 
-struct ManifestClassGenerator {
-    bool generate(IDiagnostics* diag, const StringPiece16& package, xml::XmlResource* res,
-                  std::ostream* out);
-};
+std::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
 
 } // namespace aapt
 
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index fc57ae6f..a9ec318 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -22,6 +22,23 @@
 
 namespace aapt {
 
+static ::testing::AssertionResult getManifestClassText(IAaptContext* context, xml::XmlResource* res,
+                                                       std::string* outStr) {
+    std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+            context->getDiagnostics(), res);
+    if (!manifestClass) {
+        return ::testing::AssertionFailure() << "manifestClass == nullptr";
+    }
+
+    std::stringstream out;
+    if (!manifestClass->writeJavaFile(manifestClass.get(), "android", true, &out)) {
+        return ::testing::AssertionFailure() << "failed to write java file";
+    }
+
+    *outStr = out.str();
+    return ::testing::AssertionSuccess();
+}
+
 TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
     std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
     std::unique_ptr<xml::XmlResource> manifest = test::buildXmlDom(R"EOF(
@@ -32,11 +49,8 @@
           <permission-group android:name="foo.bar.PERMISSION" />
         </manifest>)EOF");
 
-    std::stringstream out;
-    ManifestClassGenerator generator;
-    ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
-    std::string actual = out.str();
+    std::string actual;
+    ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
 
     const size_t permissionClassPos = actual.find("public static final class permission {");
     const size_t permissionGroupClassPos =
@@ -87,11 +101,8 @@
           <permission android:name="android.permission.SECRET" />
         </manifest>)EOF");
 
-    std::stringstream out;
-    ManifestClassGenerator generator;
-    ASSERT_TRUE(generator.generate(context->getDiagnostics(), u"android", manifest.get(), &out));
-
-    std::string actual = out.str();
+    std::string actual;
+    ASSERT_TRUE(getManifestClassText(context.get(), manifest.get(), &actual));
 
     EXPECT_NE(std::string::npos, actual.find(
 R"EOF(    /**
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index b84074d..8c8bffa 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -66,6 +66,7 @@
     bool staticLib = false;
     bool noStaticLibPackages = false;
     bool generateNonFinalIds = false;
+    std::vector<std::string> javadocAnnotations;
     bool outputToDirectory = false;
     bool autoAddOverlay = false;
     bool doNotCompressAnything = false;
@@ -762,9 +763,31 @@
             return true;
         }
 
+        std::unique_ptr<ClassDefinition> manifestClass = generateManifestClass(
+                mContext->getDiagnostics(), manifestXml);
+
+        if (!manifestClass) {
+            // Something bad happened, but we already logged it, so exit.
+            return false;
+        }
+
+        if (manifestClass->empty()) {
+            // Empty Manifest class, no need to generate it.
+            return true;
+        }
+
+        // Add any JavaDoc annotations to the generated class.
+        for (const std::string& annotation : mOptions.javadocAnnotations) {
+            std::string properAnnotation = "@";
+            properAnnotation += annotation;
+            manifestClass->getCommentBuilder()->appendComment(properAnnotation);
+        }
+
+        const std::string packageUtf8 = util::utf16ToUtf8(mContext->getCompilationPackage());
+
         std::string outPath = mOptions.generateJavaClassPath.value();
-        file::appendPath(&outPath,
-                         file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
+        file::appendPath(&outPath, file::packageToPath(packageUtf8));
+
         if (!file::mkdirs(outPath)) {
             mContext->getDiagnostics()->error(
                     DiagMessage() << "failed to create directory '" << outPath << "'");
@@ -780,13 +803,7 @@
             return false;
         }
 
-        ManifestClassGenerator generator;
-        if (!generator.generate(mContext->getDiagnostics(), mContext->getCompilationPackage(),
-                                manifestXml, &fout)) {
-            return false;
-        }
-
-        if (!fout) {
+        if (!ClassDefinition::writeJavaFile(manifestClass.get(), packageUtf8, true, &fout)) {
             mContext->getDiagnostics()->error(
                     DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
             return false;
@@ -1283,6 +1300,7 @@
         if (mOptions.generateJavaClassPath) {
             JavaClassGeneratorOptions options;
             options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+            options.javadocAnnotations = mOptions.javadocAnnotations;
 
             if (mOptions.staticLib || mOptions.generateNonFinalIds) {
                 options.useFinal = false;
@@ -1423,6 +1441,8 @@
                           &customJavaPackage)
             .optionalFlagList("--extra-packages", "Generate the same R.java but with different "
                               "package names", &extraJavaPackages)
+            .optionalFlagList("--add-javadoc-annotation", "Adds a JavaDoc annotation to all "
+                            "generated Java classes", &options.javadocAnnotations)
             .optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
                             "overlays without <add-resource> tags", &options.autoAddOverlay)
             .optionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml",
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index a8a8c5c..ca2d2e7 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -980,6 +980,16 @@
             warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")
 
 
+def verify_manager_list(clazz):
+    """Verifies that managers return List<? extends Parcelable> instead of arrays."""
+
+    if not clazz.name.endswith("Manager"): return
+
+    for m in clazz.methods:
+        if m.typ.startswith("android.") and m.typ.endswith("[]"):
+            warn(clazz, m, None, "Methods should return List<? extends Parcelable> instead of Parcelable[] to support ParceledListSlice under the hood")
+
+
 def examine_clazz(clazz):
     """Find all style issues in the given class."""
     if clazz.pkg.name.startswith("java"): return
@@ -1025,6 +1035,7 @@
     verify_listener_last(clazz)
     verify_resource_names(clazz)
     verify_files(clazz)
+    verify_manager_list(clazz)
 
 
 def examine_stream(stream):
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 75e837b..b5ed1b5 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -177,9 +177,10 @@
 
 def check_emoji_availability():
     emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]]
+    assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
+    emoji_font = emoji_fonts[0]
     emoji_chars = _emoji_properties['Emoji']
-    for emoji_font in emoji_fonts:
-        assert_font_supports_all_of_chars(emoji_font, emoji_chars)
+    assert_font_supports_all_of_chars(emoji_font, emoji_chars)
 
 
 def check_emoji_defaults():
@@ -273,11 +274,12 @@
     hyphens_dir = path.join(target_out, 'usr', 'hyphen-data')
     check_hyphens(hyphens_dir)
 
-    ucd_path = sys.argv[2]
-    parse_ucd(ucd_path)
-    # Temporarily disable emoji checks for Bug 27785690
-    # check_emoji_availability()
-    # check_emoji_defaults()
+    check_emoji = sys.argv[2]
+    if check_emoji == 'true':
+        ucd_path = sys.argv[3]
+        parse_ucd(ucd_path)
+        check_emoji_availability()
+        check_emoji_defaults()
 
 
 if __name__ == '__main__':
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index f5938cf..265ebd1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -423,21 +423,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_offset(long nPath, float dx, float dy, long dst_path) {
+    /*package*/ static void native_offset(long nPath, float dx, float dy) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
         }
 
-        // could be null if the int is 0;
-        Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
-
-        pathDelegate.offset(dx, dy, dstDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_offset(long nPath, float dx, float dy) {
-        native_offset(nPath, dx, dy, 0);
+        pathDelegate.offset(dx, dy);
     }
 
     @LayoutlibDelegate
@@ -860,21 +852,14 @@
      *
      * @param dx  The amount in the X direction to offset the entire path
      * @param dy  The amount in the Y direction to offset the entire path
-     * @param dst The translated path is written here. If this is null, then
-     *            the original path is modified.
      */
-    public void offset(float dx, float dy, Path_Delegate dst) {
+    public void offset(float dx, float dy) {
         GeneralPath newPath = new GeneralPath();
 
         PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
 
         newPath.append(iterator, false /*connect*/);
-
-        if (dst != null) {
-            dst.mPath = newPath;
-        } else {
-            mPath = newPath;
-        }
+        mPath = newPath;
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 309c1b8..f9e008e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -403,8 +403,15 @@
     }
 
     @Override
-    public void setNewConfiguration(Configuration arg0) throws RemoteException {
+    public int[] setNewConfiguration(Configuration arg0) throws RemoteException {
         // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Rect getBoundsForNewConfiguration(int stackId) throws RemoteException {
+        // TODO Auto-generated method stub
+        return null;
     }
 
     @Override
@@ -575,4 +582,10 @@
     @Override
     public void registerShortcutKey(long shortcutCode, IShortcutService service)
         throws RemoteException {}
+
+    @Override
+    public void createWallpaperInputConsumer(InputChannel inputChannel) throws RemoteException {}
+
+    @Override
+    public void removeWallpaperInputConsumer() throws RemoteException {}
 }
diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
index 1465f50..24f7887 100644
--- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -55,7 +55,7 @@
     private String mName;
 
     @LayoutlibDelegate
-    /*package*/ static long nCreate(String name) {
+    /*package*/ static long nCreate(RenderNode thisRenderNode, String name) {
         RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
         renderNodeDelegate.mName = name;
         return sManager.addNewDelegate(renderNodeDelegate);
diff --git a/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
new file mode 100644
index 0000000..01fe45d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.LongSparseLongArray;
+
+/**
+ * Delegate used to provide new implementation the native methods of {@link VirtualRefBasePtr}
+ *
+ * Through the layoutlib_create tool, the original native  methods of VirtualRefBasePtr have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+@SuppressWarnings("unused")
+public class VirtualRefBasePtr_Delegate {
+    private static final DelegateManager<Object> sManager = new DelegateManager<>(Object.class);
+    private static final LongSparseLongArray sRefCount = new LongSparseLongArray();
+
+    @LayoutlibDelegate
+    /*package*/ static synchronized void nIncStrong(long ptr) {
+        long counter = sRefCount.get(ptr);
+        sRefCount.put(ptr, ++counter);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static synchronized void nDecStrong(long ptr) {
+        long counter = sRefCount.get(ptr);
+
+        if (counter > 1) {
+            sRefCount.put(ptr, --counter);
+        } else {
+            sRefCount.delete(ptr);
+            sManager.removeJavaReferenceFor(ptr);
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index baf2e2e..c59b1a6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -22,9 +22,11 @@
 import android.annotation.Nullable;
 import android.util.SparseArray;
 
+import java.io.PrintStream;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Manages native delegates.
@@ -73,14 +75,14 @@
 public final class DelegateManager<T> {
     @SuppressWarnings("FieldCanBeLocal")
     private final Class<T> mClass;
-    private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
+    private static final SparseWeakArray<Object> sDelegates = new SparseWeakArray<>();
     /** list used to store delegates when their main object holds a reference to them.
      * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
      * @see #addNewDelegate(Object)
      * @see #removeJavaReferenceFor(long)
      */
-    private final List<T> mJavaReferences = new ArrayList<T>();
-    private int mDelegateCounter = 0;
+    private static final List<Object> sJavaReferences = new ArrayList<>();
+    private static final AtomicLong sDelegateCounter = new AtomicLong(1);
 
     public DelegateManager(Class<T> theClass) {
         mClass = theClass;
@@ -97,9 +99,12 @@
      * @return the delegate or null if not found.
      */
     @Nullable
-    public synchronized T getDelegate(long native_object) {
+    public T getDelegate(long native_object) {
         if (native_object > 0) {
-            T delegate = mDelegates.get(native_object);
+            Object delegate;
+            synchronized (DelegateManager.class) {
+                delegate = sDelegates.get(native_object);
+            }
 
             if (Debug.DEBUG) {
                 if (delegate == null) {
@@ -109,7 +114,8 @@
             }
 
             assert delegate != null;
-            return delegate;
+            //noinspection unchecked
+            return (T)delegate;
         }
         return null;
     }
@@ -119,12 +125,13 @@
      * @param newDelegate the delegate to add
      * @return a unique native int to identify the delegate
      */
-    public synchronized long addNewDelegate(T newDelegate) {
-        long native_object = ++mDelegateCounter;
-
-        mDelegates.put(native_object, newDelegate);
-        assert !mJavaReferences.contains(newDelegate);
-        mJavaReferences.add(newDelegate);
+    public long addNewDelegate(T newDelegate) {
+        long native_object = sDelegateCounter.getAndIncrement();
+        synchronized (DelegateManager.class) {
+            sDelegates.put(native_object, newDelegate);
+            assert !sJavaReferences.contains(newDelegate);
+            sJavaReferences.add(newDelegate);
+        }
 
         if (Debug.DEBUG) {
             System.out.println(
@@ -140,14 +147,23 @@
      * Removes the main reference on the given delegate.
      * @param native_object the native integer representing the delegate.
      */
-    public synchronized void removeJavaReferenceFor(long native_object) {
-        T delegate = getDelegate(native_object);
+    public void removeJavaReferenceFor(long native_object) {
+        synchronized (DelegateManager.class) {
+            T delegate = getDelegate(native_object);
 
-        if (Debug.DEBUG) {
-            System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
-                    " with int " + native_object);
+            if (Debug.DEBUG) {
+                System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
+                        " with int " + native_object);
+            }
+
+            sJavaReferences.remove(delegate);
         }
+    }
 
-        mJavaReferences.remove(delegate);
+    public synchronized static void dump(PrintStream out) {
+        for (Object reference : sJavaReferences) {
+            int idx = sDelegates.indexOfValue(reference);
+            out.printf("[%d] %s\n", sDelegates.keyAt(idx), reference.getClass().getSimpleName());
+        }
     }
 }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index a5561fa..09dd5f0 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -31,6 +31,7 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
@@ -52,6 +53,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
@@ -298,6 +300,16 @@
         renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
     }
 
+    private static void gc() {
+        // See RuntimeUtil#gc in jlibs (http://jlibs.in/)
+        Object obj = new Object();
+        WeakReference ref = new WeakReference<Object>(obj);
+        obj = null;
+        while(ref.get() != null) {
+            System.gc();
+        }
+    }
+
     @AfterClass
     public static void tearDown() {
         sLayoutLibLog = null;
@@ -305,6 +317,11 @@
         sProjectResources = null;
         sLogger = null;
         sBridge = null;
+
+        gc();
+
+        System.out.println("Objects still linked from the DelegateManager:");
+        DelegateManager.dump(System.out);
     }
 
     /** Test expand_layout.xml */
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 1a00cc9..483bddc 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
@@ -302,6 +302,7 @@
         "android.text.StaticLayout",
         "android.util.PathParser",
         "android.view.Display",
+        "com.android.internal.util.VirtualRefBasePtr",
         "com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
         "libcore.icu.ICU",
     };
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index bd4220f..73ddbbc 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -161,6 +161,11 @@
      */
     public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
 
+
+    /** {@hide} */
+    public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
+    /** {@hide} */
+    public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
     /**
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
      */
@@ -679,7 +684,10 @@
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, settings);
+        Bundle scanParams = new Bundle();
+        scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
+        scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
+        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -730,7 +738,10 @@
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, settings);
+        Bundle scanParams = new Bundle();
+        scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
+        scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
+        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -749,7 +760,6 @@
     private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
         // Bundle up both the settings and send it across.
         Bundle pnoParams = new Bundle();
-        if (pnoParams == null) return;
         // Set the PNO scan flag.
         scanSettings.isPnoScan = true;
         pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);