Merge "Relax permissions around NetworkStatsManager APIs."
diff --git a/api/current.txt b/api/current.txt
index a61bb5f..df6c473a3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -728,6 +728,7 @@
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
     field public static final int labelTextSize = 16843317; // 0x1010235
+    field public static final int languageTag = 16844041; // 0x1010509
     field public static final int largeHeap = 16843610; // 0x101035a
     field public static final int largeScreens = 16843398; // 0x1010286
     field public static final int largestWidthLimitDp = 16843622; // 0x1010366
@@ -924,6 +925,7 @@
     field public static final deprecated int phoneNumber = 16843111; // 0x1010167
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
+    field public static final int pointerShape = 16844042; // 0x101050a
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
     field public static final int popupBackground = 16843126; // 0x1010176
     field public static final int popupCharacters = 16843332; // 0x1010244
@@ -7780,8 +7782,7 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public abstract android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public abstract android.content.Context createDeviceEncryptedStorageContext();
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -7837,8 +7838,7 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract boolean isCredentialEncrypted();
-    method public abstract boolean isDeviceEncrypted();
+    method public abstract boolean isDeviceEncryptedStorage();
     method public boolean isRestricted();
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
@@ -7970,8 +7970,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8021,8 +8020,7 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncrypted();
-    method public boolean isDeviceEncrypted();
+    method public boolean isDeviceEncryptedStorage();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -11545,6 +11543,7 @@
     field public static final int PRIVATE = 34; // 0x22
     field public static final int RAW10 = 37; // 0x25
     field public static final int RAW12 = 38; // 0x26
+    field public static final int RAW_PRIVATE = 36; // 0x24
     field public static final int RAW_SENSOR = 32; // 0x20
     field public static final int RGB_565 = 4; // 0x4
     field public static final int UNKNOWN = 0; // 0x0
@@ -20305,6 +20304,8 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
     field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -20736,6 +20737,7 @@
   public static class MediaRouter.RouteInfo {
     method public android.media.MediaRouter.RouteCategory getCategory();
     method public java.lang.CharSequence getDescription();
+    method public int getDeviceType();
     method public android.media.MediaRouter.RouteGroup getGroup();
     method public android.graphics.drawable.Drawable getIconDrawable();
     method public java.lang.CharSequence getName();
@@ -20754,6 +20756,10 @@
     method public void requestSetVolume(int);
     method public void requestUpdateVolume(int);
     method public void setTag(java.lang.Object);
+    field public static final int DEVICE_TYPE_BLUETOOTH = 3; // 0x3
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
+    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
     field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
     field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
@@ -28095,9 +28101,13 @@
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
-    method public boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public boolean isUserRunningAndUnlocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndLocked();
+    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndUnlocked();
+    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
+    method public boolean isUserUnlocked();
+    method public boolean isUserUnlocked(android.os.UserHandle);
     method public deprecated boolean setRestrictionsChallenge(java.lang.String);
     method public deprecated void setUserRestriction(java.lang.String, boolean);
     method public deprecated void setUserRestrictions(android.os.Bundle);
@@ -33259,11 +33269,11 @@
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
-    field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
-    field public static final int IMPORTANCE_HIGH = 1; // 0x1
-    field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
-    field public static final int IMPORTANCE_MAX = 2; // 0x2
-    field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
+    field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
+    field public static final int IMPORTANCE_HIGH = 3; // 0x3
+    field public static final int IMPORTANCE_LOW = 1; // 0x1
+    field public static final int IMPORTANCE_MAX = 4; // 0x4
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
     field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
   }
 
@@ -34896,6 +34906,7 @@
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
+    field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
@@ -35218,6 +35229,7 @@
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
+    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
@@ -36248,8 +36260,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -36298,8 +36309,7 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncrypted();
-    method public boolean isDeviceEncrypted();
+    method public boolean isDeviceEncryptedStorage();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -40245,6 +40255,7 @@
     field public static final int AXIS_RX = 12; // 0xc
     field public static final int AXIS_RY = 13; // 0xd
     field public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SCROLL = 26; // 0x1a
     field public static final int AXIS_SIZE = 3; // 0x3
     field public static final int AXIS_THROTTLE = 19; // 0x13
     field public static final int AXIS_TILT = 25; // 0x19
@@ -40326,6 +40337,38 @@
     field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
   }
 
+  public final class PointerIcon implements android.os.Parcelable {
+    method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float);
+    method public int describeContents();
+    method public static android.view.PointerIcon getSystemIcon(android.content.Context, int);
+    method public static android.view.PointerIcon loadCustomIcon(android.content.res.Resources, int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR;
+    field public static final int STYLE_ALIAS = 1010; // 0x3f2
+    field public static final int STYLE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int STYLE_ARROW = 1000; // 0x3e8
+    field public static final int STYLE_CELL = 1006; // 0x3ee
+    field public static final int STYLE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int STYLE_COPY = 1011; // 0x3f3
+    field public static final int STYLE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int STYLE_DEFAULT = 1000; // 0x3e8
+    field public static final int STYLE_GRAB = 1020; // 0x3fc
+    field public static final int STYLE_GRABBING = 1021; // 0x3fd
+    field public static final int STYLE_HAND = 1002; // 0x3ea
+    field public static final int STYLE_HELP = 1003; // 0x3eb
+    field public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int STYLE_NO_DROP = 1012; // 0x3f4
+    field public static final int STYLE_NULL = 0; // 0x0
+    field public static final int STYLE_TEXT = 1008; // 0x3f0
+    field public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int STYLE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int STYLE_WAIT = 1004; // 0x3ec
+    field public static final int STYLE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int STYLE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
   public class ScaleGestureDetector {
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler);
@@ -40685,6 +40728,7 @@
     method public android.view.ViewParent getParentForAccessibility();
     method public float getPivotX();
     method public float getPivotY();
+    method public android.view.PointerIcon getPointerIcon(android.view.MotionEvent, float, float);
     method public android.content.res.Resources getResources();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
@@ -40967,6 +41011,7 @@
     method public void setPaddingRelative(int, int, int, int);
     method public void setPivotX(float);
     method public void setPivotY(float);
+    method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
     method public final void setRight(int);
     method public void setRotation(float);
@@ -41834,6 +41879,7 @@
     method public abstract void setContentView(int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setDecorCaptionShade(int);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
     method public void setElevation(float);
@@ -41854,6 +41900,8 @@
     method public void setMediaController(android.media.session.MediaController);
     method public abstract void setNavigationBarColor(int);
     method public void setReenterTransition(android.transition.Transition);
+    method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
+    method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
     method public void setReturnTransition(android.transition.Transition);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
@@ -41882,6 +41930,9 @@
     method public abstract void takeKeyEvents(boolean);
     method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
     method public abstract void togglePanel(int, android.view.KeyEvent);
+    field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
+    field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
+    field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
     field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
     field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
@@ -41936,6 +41987,10 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
+  public static abstract interface Window.RestrictedCaptionAreaListener {
+    method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+  }
+
   public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43200,7 +43255,8 @@
     method public java.lang.String getExtraValue();
     method public java.lang.String getExtraValueOf(java.lang.String);
     method public int getIconResId();
-    method public java.lang.String getLocale();
+    method public java.lang.String getLanguageTag();
+    method public deprecated java.lang.String getLocale();
     method public java.lang.String getMode();
     method public int getNameResId();
     method public boolean isAsciiCapable();
@@ -43215,6 +43271,7 @@
     method public android.view.inputmethod.InputMethodSubtype build();
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAsciiCapable(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAuxiliary(boolean);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLanguageTag(java.lang.String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(java.lang.String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeIconResId(int);
@@ -43278,7 +43335,8 @@
     method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
     method public java.lang.String getExtraValue();
     method public java.lang.String getExtraValueOf(java.lang.String);
-    method public java.lang.String getLocale();
+    method public java.lang.String getLanguageTag();
+    method public deprecated java.lang.String getLocale();
     method public int getNameResId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerSubtype> CREATOR;
diff --git a/api/system-current.txt b/api/system-current.txt
index 970b029..ee975d1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -822,6 +822,7 @@
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
     field public static final int labelTextSize = 16843317; // 0x1010235
+    field public static final int languageTag = 16844041; // 0x1010509
     field public static final int largeHeap = 16843610; // 0x101035a
     field public static final int largeScreens = 16843398; // 0x1010286
     field public static final int largestWidthLimitDp = 16843622; // 0x1010366
@@ -1018,6 +1019,7 @@
     field public static final deprecated int phoneNumber = 16843111; // 0x1010167
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
+    field public static final int pointerShape = 16844042; // 0x101050a
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
     field public static final int popupBackground = 16843126; // 0x1010176
     field public static final int popupCharacters = 16843332; // 0x1010244
@@ -8024,8 +8026,8 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public abstract android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public abstract android.content.Context createCredentialEncryptedStorageContext();
+    method public abstract android.content.Context createDeviceEncryptedStorageContext();
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -8081,8 +8083,8 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract boolean isCredentialEncrypted();
-    method public abstract boolean isDeviceEncrypted();
+    method public abstract boolean isCredentialEncryptedStorage();
+    method public abstract boolean isDeviceEncryptedStorage();
     method public boolean isRestricted();
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
@@ -8222,8 +8224,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public android.content.Context createCredentialEncryptedStorageContext();
+    method public android.content.Context createDeviceEncryptedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8273,8 +8275,8 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncrypted();
-    method public boolean isDeviceEncrypted();
+    method public boolean isCredentialEncryptedStorage();
+    method public boolean isDeviceEncryptedStorage();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -11888,6 +11890,7 @@
     field public static final int PRIVATE = 34; // 0x22
     field public static final int RAW10 = 37; // 0x25
     field public static final int RAW12 = 38; // 0x26
+    field public static final int RAW_PRIVATE = 36; // 0x24
     field public static final int RAW_SENSOR = 32; // 0x20
     field public static final int RGB_565 = 4; // 0x4
     field public static final int UNKNOWN = 0; // 0x0
@@ -21592,6 +21595,8 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
     field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -22025,6 +22030,7 @@
   public static class MediaRouter.RouteInfo {
     method public android.media.MediaRouter.RouteCategory getCategory();
     method public java.lang.CharSequence getDescription();
+    method public int getDeviceType();
     method public android.media.MediaRouter.RouteGroup getGroup();
     method public android.graphics.drawable.Drawable getIconDrawable();
     method public java.lang.CharSequence getName();
@@ -22043,6 +22049,10 @@
     method public void requestSetVolume(int);
     method public void requestUpdateVolume(int);
     method public void setTag(java.lang.Object);
+    field public static final int DEVICE_TYPE_BLUETOOTH = 3; // 0x3
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
+    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
     field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
     field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
@@ -30085,9 +30095,13 @@
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
-    method public boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public boolean isUserRunningAndUnlocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndLocked();
+    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndUnlocked();
+    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
+    method public boolean isUserUnlocked();
+    method public boolean isUserUnlocked(android.os.UserHandle);
     method public deprecated boolean setRestrictionsChallenge(java.lang.String);
     method public deprecated void setUserRestriction(java.lang.String, boolean);
     method public deprecated void setUserRestrictions(android.os.Bundle);
@@ -35389,11 +35403,11 @@
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
-    field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
-    field public static final int IMPORTANCE_HIGH = 1; // 0x1
-    field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
-    field public static final int IMPORTANCE_MAX = 2; // 0x2
-    field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
+    field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
+    field public static final int IMPORTANCE_HIGH = 3; // 0x3
+    field public static final int IMPORTANCE_LOW = 1; // 0x1
+    field public static final int IMPORTANCE_MAX = 4; // 0x4
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
     field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
   }
 
@@ -37130,6 +37144,7 @@
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
+    field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
@@ -37487,6 +37502,7 @@
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
+    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
@@ -38571,8 +38587,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public android.content.Context createCredentialEncryptedStorageContext();
+    method public android.content.Context createDeviceEncryptedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -38621,8 +38637,8 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncrypted();
-    method public boolean isDeviceEncrypted();
+    method public boolean isCredentialEncryptedStorage();
+    method public boolean isDeviceEncryptedStorage();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -42577,6 +42593,7 @@
     field public static final int AXIS_RX = 12; // 0xc
     field public static final int AXIS_RY = 13; // 0xd
     field public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SCROLL = 26; // 0x1a
     field public static final int AXIS_SIZE = 3; // 0x3
     field public static final int AXIS_THROTTLE = 19; // 0x13
     field public static final int AXIS_TILT = 25; // 0x19
@@ -42658,6 +42675,38 @@
     field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
   }
 
+  public final class PointerIcon implements android.os.Parcelable {
+    method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float);
+    method public int describeContents();
+    method public static android.view.PointerIcon getSystemIcon(android.content.Context, int);
+    method public static android.view.PointerIcon loadCustomIcon(android.content.res.Resources, int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR;
+    field public static final int STYLE_ALIAS = 1010; // 0x3f2
+    field public static final int STYLE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int STYLE_ARROW = 1000; // 0x3e8
+    field public static final int STYLE_CELL = 1006; // 0x3ee
+    field public static final int STYLE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int STYLE_COPY = 1011; // 0x3f3
+    field public static final int STYLE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int STYLE_DEFAULT = 1000; // 0x3e8
+    field public static final int STYLE_GRAB = 1020; // 0x3fc
+    field public static final int STYLE_GRABBING = 1021; // 0x3fd
+    field public static final int STYLE_HAND = 1002; // 0x3ea
+    field public static final int STYLE_HELP = 1003; // 0x3eb
+    field public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int STYLE_NO_DROP = 1012; // 0x3f4
+    field public static final int STYLE_NULL = 0; // 0x0
+    field public static final int STYLE_TEXT = 1008; // 0x3f0
+    field public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int STYLE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int STYLE_WAIT = 1004; // 0x3ec
+    field public static final int STYLE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int STYLE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
   public class ScaleGestureDetector {
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler);
@@ -43017,6 +43066,7 @@
     method public android.view.ViewParent getParentForAccessibility();
     method public float getPivotX();
     method public float getPivotY();
+    method public android.view.PointerIcon getPointerIcon(android.view.MotionEvent, float, float);
     method public android.content.res.Resources getResources();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
@@ -43299,6 +43349,7 @@
     method public void setPaddingRelative(int, int, int, int);
     method public void setPivotX(float);
     method public void setPivotY(float);
+    method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
     method public final void setRight(int);
     method public void setRotation(float);
@@ -44166,6 +44217,7 @@
     method public abstract void setContentView(int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setDecorCaptionShade(int);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
     method public void setDisableWallpaperTouchEvents(boolean);
@@ -44187,6 +44239,8 @@
     method public void setMediaController(android.media.session.MediaController);
     method public abstract void setNavigationBarColor(int);
     method public void setReenterTransition(android.transition.Transition);
+    method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
+    method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
     method public void setReturnTransition(android.transition.Transition);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
@@ -44215,6 +44269,9 @@
     method public abstract void takeKeyEvents(boolean);
     method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
     method public abstract void togglePanel(int, android.view.KeyEvent);
+    field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
+    field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
+    field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
     field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
     field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
@@ -44269,6 +44326,10 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
+  public static abstract interface Window.RestrictedCaptionAreaListener {
+    method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+  }
+
   public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -45535,7 +45596,8 @@
     method public java.lang.String getExtraValue();
     method public java.lang.String getExtraValueOf(java.lang.String);
     method public int getIconResId();
-    method public java.lang.String getLocale();
+    method public java.lang.String getLanguageTag();
+    method public deprecated java.lang.String getLocale();
     method public java.lang.String getMode();
     method public int getNameResId();
     method public boolean isAsciiCapable();
@@ -45550,6 +45612,7 @@
     method public android.view.inputmethod.InputMethodSubtype build();
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAsciiCapable(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAuxiliary(boolean);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLanguageTag(java.lang.String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(java.lang.String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeIconResId(int);
@@ -45613,7 +45676,8 @@
     method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
     method public java.lang.String getExtraValue();
     method public java.lang.String getExtraValueOf(java.lang.String);
-    method public java.lang.String getLocale();
+    method public java.lang.String getLanguageTag();
+    method public deprecated java.lang.String getLocale();
     method public int getNameResId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerSubtype> CREATOR;
@@ -46450,8 +46514,6 @@
     method public static android.content.pm.PackageInfo getLoadedPackageInfo();
     method public static java.lang.String getWebViewPackageName();
     method public static int loadWebViewNativeLibraryFromPackage(java.lang.String);
-    method public static void onWebViewUpdateInstalled();
-    method public static void prepareWebViewInSystemServer();
     method public static void prepareWebViewInZygote();
     field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
     field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
@@ -46460,7 +46522,9 @@
     field public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; // 0x6
     field public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; // 0x5
     field public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; // 0x3
+    field public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9; // 0x9
     field public static final int LIBLOAD_SUCCESS = 0; // 0x0
+    field public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8; // 0x8
     field public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; // 0x1
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 4c8d361..c494895 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -728,6 +728,7 @@
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
     field public static final int labelTextSize = 16843317; // 0x1010235
+    field public static final int languageTag = 16844041; // 0x1010509
     field public static final int largeHeap = 16843610; // 0x101035a
     field public static final int largeScreens = 16843398; // 0x1010286
     field public static final int largestWidthLimitDp = 16843622; // 0x1010366
@@ -924,6 +925,7 @@
     field public static final deprecated int phoneNumber = 16843111; // 0x1010167
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
+    field public static final int pointerShape = 16844042; // 0x101050a
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
     field public static final int popupBackground = 16843126; // 0x1010176
     field public static final int popupCharacters = 16843332; // 0x1010244
@@ -7780,8 +7782,7 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public abstract android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public abstract android.content.Context createDeviceEncryptedStorageContext();
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -7837,8 +7838,7 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract boolean isCredentialEncrypted();
-    method public abstract boolean isDeviceEncrypted();
+    method public abstract boolean isDeviceEncryptedStorage();
     method public boolean isRestricted();
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
@@ -7970,8 +7970,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8021,8 +8020,7 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncrypted();
-    method public boolean isDeviceEncrypted();
+    method public boolean isDeviceEncryptedStorage();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -11545,6 +11543,7 @@
     field public static final int PRIVATE = 34; // 0x22
     field public static final int RAW10 = 37; // 0x25
     field public static final int RAW12 = 38; // 0x26
+    field public static final int RAW_PRIVATE = 36; // 0x24
     field public static final int RAW_SENSOR = 32; // 0x20
     field public static final int RGB_565 = 4; // 0x4
     field public static final int UNKNOWN = 0; // 0x0
@@ -20305,6 +20304,8 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
     field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -20736,6 +20737,7 @@
   public static class MediaRouter.RouteInfo {
     method public android.media.MediaRouter.RouteCategory getCategory();
     method public java.lang.CharSequence getDescription();
+    method public int getDeviceType();
     method public android.media.MediaRouter.RouteGroup getGroup();
     method public android.graphics.drawable.Drawable getIconDrawable();
     method public java.lang.CharSequence getName();
@@ -20754,6 +20756,10 @@
     method public void requestSetVolume(int);
     method public void requestUpdateVolume(int);
     method public void setTag(java.lang.Object);
+    field public static final int DEVICE_TYPE_BLUETOOTH = 3; // 0x3
+    field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+    field public static final int DEVICE_TYPE_TV = 1; // 0x1
+    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
     field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
     field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
@@ -28095,9 +28101,13 @@
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
     method public boolean isUserRunning(android.os.UserHandle);
-    method public boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public boolean isUserRunningAndUnlocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndLocked();
+    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
+    method public deprecated boolean isUserRunningAndUnlocked();
+    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
+    method public boolean isUserUnlocked();
+    method public boolean isUserUnlocked(android.os.UserHandle);
     method public deprecated boolean setRestrictionsChallenge(java.lang.String);
     method public deprecated void setUserRestriction(java.lang.String, boolean);
     method public deprecated void setUserRestrictions(android.os.Bundle);
@@ -33261,11 +33271,11 @@
     method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
-    field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
-    field public static final int IMPORTANCE_HIGH = 1; // 0x1
-    field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
-    field public static final int IMPORTANCE_MAX = 2; // 0x2
-    field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
+    field public static final int IMPORTANCE_DEFAULT = 2; // 0x2
+    field public static final int IMPORTANCE_HIGH = 3; // 0x3
+    field public static final int IMPORTANCE_LOW = 1; // 0x1
+    field public static final int IMPORTANCE_MAX = 4; // 0x4
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
     field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
   }
 
@@ -34898,6 +34908,7 @@
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
+    field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
@@ -35220,6 +35231,7 @@
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
+    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
@@ -36250,8 +36262,7 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
-    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -36300,8 +36311,7 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
-    method public boolean isCredentialEncrypted();
-    method public boolean isDeviceEncrypted();
+    method public boolean isDeviceEncryptedStorage();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -40247,6 +40257,7 @@
     field public static final int AXIS_RX = 12; // 0xc
     field public static final int AXIS_RY = 13; // 0xd
     field public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SCROLL = 26; // 0x1a
     field public static final int AXIS_SIZE = 3; // 0x3
     field public static final int AXIS_THROTTLE = 19; // 0x13
     field public static final int AXIS_TILT = 25; // 0x19
@@ -40328,6 +40339,38 @@
     field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
   }
 
+  public final class PointerIcon implements android.os.Parcelable {
+    method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float);
+    method public int describeContents();
+    method public static android.view.PointerIcon getSystemIcon(android.content.Context, int);
+    method public static android.view.PointerIcon loadCustomIcon(android.content.res.Resources, int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR;
+    field public static final int STYLE_ALIAS = 1010; // 0x3f2
+    field public static final int STYLE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int STYLE_ARROW = 1000; // 0x3e8
+    field public static final int STYLE_CELL = 1006; // 0x3ee
+    field public static final int STYLE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int STYLE_COPY = 1011; // 0x3f3
+    field public static final int STYLE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int STYLE_DEFAULT = 1000; // 0x3e8
+    field public static final int STYLE_GRAB = 1020; // 0x3fc
+    field public static final int STYLE_GRABBING = 1021; // 0x3fd
+    field public static final int STYLE_HAND = 1002; // 0x3ea
+    field public static final int STYLE_HELP = 1003; // 0x3eb
+    field public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int STYLE_NO_DROP = 1012; // 0x3f4
+    field public static final int STYLE_NULL = 0; // 0x0
+    field public static final int STYLE_TEXT = 1008; // 0x3f0
+    field public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int STYLE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int STYLE_WAIT = 1004; // 0x3ec
+    field public static final int STYLE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int STYLE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
   public class ScaleGestureDetector {
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
     ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler);
@@ -40687,6 +40730,7 @@
     method public android.view.ViewParent getParentForAccessibility();
     method public float getPivotX();
     method public float getPivotY();
+    method public android.view.PointerIcon getPointerIcon(android.view.MotionEvent, float, float);
     method public android.content.res.Resources getResources();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
@@ -40969,6 +41013,7 @@
     method public void setPaddingRelative(int, int, int, int);
     method public void setPivotX(float);
     method public void setPivotY(float);
+    method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
     method public final void setRight(int);
     method public void setRotation(float);
@@ -41836,6 +41881,7 @@
     method public abstract void setContentView(int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setDecorCaptionShade(int);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
     method public void setElevation(float);
@@ -41856,6 +41902,8 @@
     method public void setMediaController(android.media.session.MediaController);
     method public abstract void setNavigationBarColor(int);
     method public void setReenterTransition(android.transition.Transition);
+    method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
+    method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
     method public void setReturnTransition(android.transition.Transition);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
@@ -41884,6 +41932,9 @@
     method public abstract void takeKeyEvents(boolean);
     method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
     method public abstract void togglePanel(int, android.view.KeyEvent);
+    field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
+    field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
+    field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
     field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
     field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
@@ -41938,6 +41989,10 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
+  public static abstract interface Window.RestrictedCaptionAreaListener {
+    method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+  }
+
   public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43202,7 +43257,8 @@
     method public java.lang.String getExtraValue();
     method public java.lang.String getExtraValueOf(java.lang.String);
     method public int getIconResId();
-    method public java.lang.String getLocale();
+    method public java.lang.String getLanguageTag();
+    method public deprecated java.lang.String getLocale();
     method public java.lang.String getMode();
     method public int getNameResId();
     method public boolean isAsciiCapable();
@@ -43217,6 +43273,7 @@
     method public android.view.inputmethod.InputMethodSubtype build();
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAsciiCapable(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAuxiliary(boolean);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLanguageTag(java.lang.String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(java.lang.String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeIconResId(int);
@@ -43280,7 +43337,8 @@
     method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
     method public java.lang.String getExtraValue();
     method public java.lang.String getExtraValueOf(java.lang.String);
-    method public java.lang.String getLocale();
+    method public java.lang.String getLanguageTag();
+    method public deprecated java.lang.String getLocale();
     method public int getNameResId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerSubtype> CREATOR;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 93c6bef..ef84ab0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1733,9 +1733,13 @@
      *
      * @param multiWindowMode True if the activity is in multi-window mode.
      */
+    @CallSuper
     public void onMultiWindowModeChanged(boolean multiWindowMode) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG,
                 "onMultiWindowModeChanged " + this + ": " + multiWindowMode);
+        if (mWindow != null) {
+            mWindow.onMultiWindowModeChanged();
+        }
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f3242a7..f11bf742 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1558,6 +1558,15 @@
             return true;
         }
 
+        case KILL_PACKAGE_DEPENDENTS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String packageName = data.readString();
+            int userId = data.readInt();
+            killPackageDependents(packageName, userId);
+            reply.writeNoException();
+            return true;
+        }
+
         case FORCE_STOP_PACKAGE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String packageName = data.readString();
@@ -2718,10 +2727,10 @@
             reply.writeNoException();
             return true;
         }
-        case REMOVE_STACK_TRANSACTION: {
+        case MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final int stackId = data.readInt();
-            removeStack(stackId);
+            moveTasksToFullscreenStack(stackId);
             reply.writeNoException();
             return true;
         }
@@ -4736,6 +4745,18 @@
         reply.recycle();
     }
 
+    public void killPackageDependents(String packageName, int userId) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        data.writeInt(userId);
+        mRemote.transact(KILL_PACKAGE_DEPENDENTS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public void forceStopPackage(String packageName, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -6358,12 +6379,12 @@
     }
 
     @Override
-    public void removeStack(int stackId) throws RemoteException {
+    public void moveTasksToFullscreenStack(int fromStackId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackId);
-        mRemote.transact(REMOVE_STACK_TRANSACTION, data, reply, 0);
+        data.writeInt(fromStackId);
+        mRemote.transact(MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f3539ff..3962abd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4399,10 +4399,14 @@
             // onConfigurationChanged
             int diff = activity.mCurrentConfig.diff(config);
             if (diff != 0) {
-                // If this activity doesn't handle any of the config changes
-                // then don't bother calling onConfigurationChanged as we're
-                // going to destroy it.
-                if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
+                // If this activity doesn't handle any of the config changes then don't bother
+                // calling onConfigurationChanged as we're going to destroy it.
+                // Except in the case where the configuration changed on the activity manager side,
+                // but wasn't big enough to cause a resource change so the activity wasn't destroyed.
+                // In this case we still want to change the configuration of the activity but not
+                // report it to the app.
+                if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0
+                        || !reportToActivity) {
                     shouldChangeConfig = true;
                 }
             }
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 413c369..ddb2d46 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -27,7 +27,8 @@
         return gApplicationLoaders;
     }
 
-    public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent)
+    public ClassLoader getClassLoader(String zip, String librarySearchPath,
+                                      String libraryPermittedPath, ClassLoader parent)
     {
         /*
          * This is the parent we use if they pass "null" in.  In theory
@@ -55,7 +56,7 @@
     
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                 PathClassLoader pathClassloader =
-                    new PathClassLoader(zip, libPath, parent);
+                    new PathClassLoader(zip, librarySearchPath, libraryPermittedPath, parent);
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
                 mLoaders.put(zip, pathClassloader);
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 1f378da..175b979 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.SystemApi;
+import android.os.Build;
 import android.os.Bundle;
 
 /**
@@ -28,15 +29,28 @@
 @SystemApi
 public class BroadcastOptions {
     private long mTemporaryAppWhitelistDuration;
+    private int mMinManifestReceiverApiLevel = 0;
+    private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
 
     /**
      * How long to temporarily put an app on the power whitelist when executing this broadcast
      * to it.
-     * @hide
      */
-    public static final String KEY_TEMPORARY_APP_WHITELIST_DURATION
+    static final String KEY_TEMPORARY_APP_WHITELIST_DURATION
             = "android:broadcast.temporaryAppWhitelistDuration";
 
+    /**
+     * Corresponds to {@link #setMinManifestReceiverApiLevel}.
+     */
+    static final String KEY_MIN_MANIFEST_RECEIVER_API_LEVEL
+            = "android:broadcast.minManifestReceiverApiLevel";
+
+    /**
+     * Corresponds to {@link #setMaxManifestReceiverApiLevel}.
+     */
+    static final String KEY_MAX_MANIFEST_RECEIVER_API_LEVEL
+            = "android:broadcast.maxManifestReceiverApiLevel";
+
     public static BroadcastOptions makeBasic() {
         BroadcastOptions opts = new BroadcastOptions();
         return opts;
@@ -48,6 +62,9 @@
     /** @hide */
     public BroadcastOptions(Bundle opts) {
         mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION);
+        mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0);
+        mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL,
+                Build.VERSION_CODES.CUR_DEVELOPMENT);
     }
 
     /**
@@ -68,10 +85,46 @@
     }
 
     /**
+     * Set the minimum target API level of receivers of the broadcast.  If an application
+     * is targeting an API level less than this, the broadcast will not be delivered to
+     * them.  This only applies to receivers declared in the app's AndroidManifest.xml.
+     * @hide
+     */
+    public void setMinManifestReceiverApiLevel(int apiLevel) {
+        mMinManifestReceiverApiLevel = apiLevel;
+    }
+
+    /**
+     * Return {@link #setMinManifestReceiverApiLevel}.
+     * @hide
+     */
+    public int getMinManifestReceiverApiLevel() {
+        return mMinManifestReceiverApiLevel;
+    }
+
+    /**
+     * Set the maximum target API level of receivers of the broadcast.  If an application
+     * is targeting an API level greater than this, the broadcast will not be delivered to
+     * them.  This only applies to receivers declared in the app's AndroidManifest.xml.
+     * @hide
+     */
+    public void setMaxManifestReceiverApiLevel(int apiLevel) {
+        mMaxManifestReceiverApiLevel = apiLevel;
+    }
+
+    /**
+     * Return {@link #setMaxManifestReceiverApiLevel}.
+     * @hide
+     */
+    public int getMaxManifestReceiverApiLevel() {
+        return mMaxManifestReceiverApiLevel;
+    }
+
+    /**
      * Returns the created options as a Bundle, which can be passed to
      * {@link android.content.Context#sendBroadcast(android.content.Intent)
      * Context.sendBroadcast(Intent)} and related methods.
-     * Note that the returned Bundle is still owned by the ActivityOptions
+     * Note that the returned Bundle is still owned by the BroadcastOptions
      * object; you must not modify it, but can supply it to the sendBroadcast
      * methods that take an options Bundle.
      */
@@ -80,6 +133,12 @@
         if (mTemporaryAppWhitelistDuration > 0) {
             b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration);
         }
+        if (mMinManifestReceiverApiLevel != 0) {
+            b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
+        }
+        if (mMaxManifestReceiverApiLevel != Build.VERSION_CODES.CUR_DEVELOPMENT) {
+            b.putInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL, mMaxManifestReceiverApiLevel);
+        }
         return b.isEmpty() ? null : b;
     }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 36e98f9..569ab11 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -61,6 +61,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -1092,7 +1093,23 @@
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
+                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
+                    user.getIdentifier());
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failure from system", e);
+        }
+    }
+
+    @Override
+    @Deprecated
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            intent.prepareToLeaveProcess();
+            ActivityManagerNative.getDefault().broadcastIntent(
+                mMainThread.getApplicationThread(), intent, resolvedType, null,
+                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
+                user.getIdentifier());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
         }
@@ -1744,17 +1761,21 @@
     }
 
     @Override
-    public Context createDeviceEncryptedContext(Context context) {
-        final int flags = (mFlags & ~Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED)
-                | Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED;
+    public Context createDeviceEncryptedStorageContext() {
+        if (!StorageManager.isFileBasedEncryptionEnabled()) {
+            return null;
+        }
+
+        final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE)
+                | Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
                 mUser, flags, mDisplay, null, Display.INVALID_DISPLAY);
     }
 
     @Override
-    public Context createCredentialEncryptedContext(Context context) {
-        final int flags = (mFlags & ~Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED)
-                | Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED;
+    public Context createCredentialEncryptedStorageContext() {
+        final int flags = (mFlags & ~Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE)
+                | Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
                 mUser, flags, mDisplay, null, Display.INVALID_DISPLAY);
     }
@@ -1765,13 +1786,13 @@
     }
 
     @Override
-    public boolean isDeviceEncrypted() {
-        return (mFlags & Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED) != 0;
+    public boolean isDeviceEncryptedStorage() {
+        return (mFlags & Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE) != 0;
     }
 
     @Override
-    public boolean isCredentialEncrypted() {
-        return (mFlags & Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED) != 0;
+    public boolean isCredentialEncryptedStorage() {
+        return (mFlags & Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE) != 0;
     }
 
     @Override
@@ -1781,13 +1802,12 @@
 
     private File getDataDirFile() {
         if (mPackageInfo != null) {
-            if (isCredentialEncrypted()) {
+            if (isCredentialEncryptedStorage()) {
                 return mPackageInfo.getCredentialEncryptedDataDirFile();
-            } else if (isDeviceEncrypted()) {
+            } else if (isDeviceEncryptedStorage()) {
                 return mPackageInfo.getDeviceEncryptedDataDirFile();
             } else {
-                throw new RuntimeException(
-                        "Storage location is neither credential nor device encrypted");
+                return mPackageInfo.getDataDirFile();
             }
         }
         throw new RuntimeException("Not supported in system context");
@@ -1840,15 +1860,13 @@
 
         // If creator didn't specify which storage to use, use the default
         // location for application.
-        if ((flags & Context.CONTEXT_STORAGE_MASK) == 0) {
+        if ((flags & (Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE
+                | Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE)) == 0) {
             final File dataDir = packageInfo.getDataDirFile();
             if (Objects.equals(dataDir, packageInfo.getCredentialEncryptedDataDirFile())) {
-                flags |= Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED;
+                flags |= Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE;
             } else if (Objects.equals(dataDir, packageInfo.getDeviceEncryptedDataDirFile())) {
-                flags |= Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED;
-            } else {
-                throw new IllegalStateException("Storage location " + dataDir
-                        + " doesn't match either credential or device encrypted storage");
+                flags |= Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE;
             }
         }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 22a2d64..64c69af 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -259,6 +259,7 @@
     public void killBackgroundProcesses(final String packageName, int userId)
             throws RemoteException;
     public void killAllBackgroundProcesses() throws RemoteException;
+    public void killPackageDependents(final String packageName, int userId) throws RemoteException;
     public void forceStopPackage(final String packageName, int userId) throws RemoteException;
 
     // Note: probably don't want to allow applications access to these.
@@ -541,7 +542,7 @@
 
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
 
-    public void removeStack(int stackId) throws RemoteException;
+    public void moveTasksToFullscreenStack(int fromStackId) throws RemoteException;
 
     public int getAppStartMode(int uid, String packageName) throws RemoteException;
 
@@ -906,10 +907,11 @@
     int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
     int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
     int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
-    int REMOVE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348;
+    int MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348;
     int MOVE_TOP_ACTIVITY_TO_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 349;
     int GET_APP_START_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 350;
     int UNLOCK_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 351;
     int IN_MULTI_WINDOW_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 352;
     int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
+    int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 23e4d97..3910657 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -21,11 +21,14 @@
 import android.app.trust.ITrustManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.IBinder;
+import android.os.IUserManager;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.view.IWindowManager;
 import android.view.IOnKeyguardExitResult;
 import android.view.WindowManagerGlobal;
@@ -40,6 +43,7 @@
 public class KeyguardManager {
     private IWindowManager mWM;
     private ITrustManager mTrustManager;
+    private IUserManager mUserManager;
 
     /**
      * Intent used to prompt user for device credentials.
@@ -49,6 +53,13 @@
             "android.app.action.CONFIRM_DEVICE_CREDENTIAL";
 
     /**
+     * Intent used to prompt user for device credentials.
+     * @hide
+     */
+    public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
+            "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
+
+    /**
      * A CharSequence dialog title to show to the user when used with a
      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
      * @hide
@@ -71,7 +82,7 @@
      * @return the intent for launching the activity or null if no password is required.
      **/
     public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
-        if (!isKeyguardSecure()) return null;
+        if (!isDeviceSecure()) return null;
         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
         intent.putExtra(EXTRA_TITLE, title);
         intent.putExtra(EXTRA_DESCRIPTION, description);
@@ -81,6 +92,28 @@
     }
 
     /**
+     * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
+     * for the given user. The caller is expected to launch this activity using
+     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
+     * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
+     *
+     * @return the intent for launching the activity or null if no password is required.
+     *
+     * @hide
+     */
+    public Intent createConfirmDeviceCredentialIntent(
+            CharSequence title, CharSequence description, int userId) {
+        if (!isDeviceSecure(userId)) return null;
+        Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
+        intent.putExtra(EXTRA_TITLE, title);
+        intent.putExtra(EXTRA_DESCRIPTION, description);
+        intent.putExtra(Intent.EXTRA_USER_ID, userId);
+        // For security reasons, only allow this to come from system settings.
+        intent.setPackage("com.android.settings");
+        return intent;
+    }
+
+    /**
      * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
      * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
@@ -162,6 +195,8 @@
         mWM = WindowManagerGlobal.getWindowManagerService();
         mTrustManager = ITrustManager.Stub.asInterface(
                 ServiceManager.getService(Context.TRUST_SERVICE));
+        mUserManager = IUserManager.Stub.asInterface(
+                ServiceManager.getService(Context.USER_SERVICE));
     }
 
     /**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 891558f..7313fd1 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -366,7 +366,15 @@
                     }
                 }
 
-                final String lib = TextUtils.join(File.pathSeparator, libPaths);
+                if (mApplicationInfo.isSystemApp()) {
+                    // Add path to system libraries to libPaths;
+                    // Access to system libs should be limited
+                    // to bundled applications; this is why updated
+                    // system apps are not included.
+                    libPaths.add(System.getProperty("java.library.path"));
+                }
+
+                final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
 
                 /*
                  * With all the combination done (if necessary, actually
@@ -374,14 +382,17 @@
                  */
 
                 if (ActivityThread.localLOGV)
-                    Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + lib);
+                    Slog.v(ActivityThread.TAG, "Class path: " + zip +
+                            ", JNI path: " + librarySearchPath);
 
                 // Temporarily disable logging of disk reads on the Looper thread
                 // as this is early and necessary.
                 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
 
-                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,
-                        mBaseClassLoader);
+                String libraryPermittedPath = mAppDir + File.pathSeparator + mDataDir;
+
+                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, librarySearchPath,
+                        libraryPermittedPath, mBaseClassLoader);
 
                 StrictMode.setThreadPolicy(oldPolicy);
             } else {
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 1370000..aa14cb5 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -35,6 +35,8 @@
 import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 
+import dalvik.system.BaseDexClassLoader;
+
 import java.io.File;
 
 /**
@@ -93,7 +95,9 @@
     
     private native long loadNativeCode(String path, String funcname, MessageQueue queue,
             String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
-            AssetManager assetMgr, byte[] savedState);
+            AssetManager assetMgr, byte[] savedState, ClassLoader classLoader, String libraryPath,
+            String isolationPath);
+    private native String getDlError();
     private native void unloadNativeCode(long handle);
     private native void onStartNative(long handle);
     private native void onResumeNative(long handle);
@@ -157,15 +161,10 @@
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException("Error getting activity info", e);
         }
-        
-        String path = null;
-        
-        File libraryFile = new File(ai.applicationInfo.nativeLibraryDir,
-                System.mapLibraryName(libname));
-        if (libraryFile.exists()) {
-            path = libraryFile.getPath();
-        }
-        
+
+        BaseDexClassLoader classLoader = (BaseDexClassLoader) getClassLoader();
+        String path = classLoader.findLibrary(libname);
+
         if (path == null) {
             throw new IllegalArgumentException("Unable to find native library: " + libname);
         }
@@ -176,10 +175,13 @@
         mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
                 getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
                 getAbsolutePath(getExternalFilesDir(null)),
-                Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
+                Build.VERSION.SDK_INT, getAssets(), nativeSavedState,
+                classLoader, classLoader.getLdLibraryPath(),
+                classLoader.getLibraryPermittedPath());
 
         if (mNativeHandle == 0) {
-            throw new IllegalArgumentException("Unable to load native library: " + path);
+            throw new UnsatisfiedLinkError(
+                    "Unable to load native library \"" + path + "\": " + getDlError());
         }
         super.onCreate(savedInstanceState);
     }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 099a5fe..620ab50 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -46,6 +46,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.NotificationHeaderView;
@@ -64,6 +65,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * A class that represents how a persistent notification is to be presented to
@@ -1693,11 +1695,21 @@
         bigContentView = null;
         headsUpContentView = null;
         mLargeIcon = null;
-        if (extras != null) {
-            extras.remove(Notification.EXTRA_LARGE_ICON);
-            extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
-            extras.remove(Notification.EXTRA_PICTURE);
-            extras.remove(Notification.EXTRA_BIG_TEXT);
+        if (extras != null && !extras.isEmpty()) {
+            final Set<String> keyset = extras.keySet();
+            final int N = keyset.size();
+            final String[] keys = keyset.toArray(new String[N]);
+            for (int i=0; i<N; i++) {
+                final String key = keys[i];
+                final Object obj = extras.get(key);
+                if (obj != null &&
+                    (  obj instanceof Parcelable
+                    || obj instanceof Parcelable[]
+                    || obj instanceof SparseArray
+                    || obj instanceof ArrayList)) {
+                    extras.remove(key);
+                }
+            }
         }
     }
 
@@ -3318,7 +3330,6 @@
             if (mN.color != COLOR_DEFAULT) {
                 button.setTextColor(R.id.action0, mN.color);
             }
-            processLegacyAction(action, button);
             return button;
         }
 
@@ -3330,14 +3341,6 @@
             return getColorUtil() != null;
         }
 
-        private void processLegacyAction(Action action, RemoteViews button) {
-            if (!isLegacy() || getColorUtil().isGrayscaleIcon(mContext, action.getIcon())) {
-                button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
-                        mContext.getColor(R.color.notification_action_color_filter),
-                        PorterDuff.Mode.MULTIPLY);
-            }
-        }
-
         private CharSequence processLegacyText(CharSequence charSequence) {
             if (isLegacy()) {
                 return getColorUtil().invertCharSequenceColors(charSequence);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 89610e9..85d9831 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -128,6 +128,14 @@
             = "android.app.action.INTERRUPTION_FILTER_CHANGED";
 
     /**
+     * Intent that is broadcast when the state of getCurrentInterruptionFilter() changes.
+     * @hide
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL
+            = "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL";
+
+    /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
      *     Normal interruption filter.
      */
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 5e8ad68..b899116 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -180,10 +180,17 @@
      * Expand the settings panel.
      */
     public void expandSettingsPanel() {
+        expandSettingsPanel(null);
+    }
+
+    /**
+     * Expand the settings panel and open a subPanel, pass null to just open the settings panel.
+     */
+    public void expandSettingsPanel(String subPanel) {
         try {
             final IStatusBarService svc = getService();
             if (svc != null) {
-                svc.expandSettingsPanel();
+                svc.expandSettingsPanel(subPanel);
             }
         } catch (RemoteException ex) {
             // system process is dead anyway.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6b900a8..08b7d62 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -89,7 +89,6 @@
     private final Context mContext;
     private final IDevicePolicyManager mService;
 
-    // TODO Use it everywhere.
     private static final String REMOTE_EXCEPTION_MESSAGE =
             "Failed to talk with device policy manager service";
 
@@ -167,7 +166,7 @@
      * Activity action: Starts the provisioning flow which sets up a managed user.
      *
      * <p>This intent will typically be sent by a mobile device management application (MDM).
-     * Provisioning configures the current user as managed user and sets the MDM as the profile
+     * Provisioning configures the user as managed user and sets the MDM as the profile
      * owner who has full control over the user. Provisioning can only happen before user setup has
      * been completed. Use {@link #isProvisioningAllowed(String)} to check if provisioning is
      * allowed.
@@ -841,7 +840,7 @@
             try {
                 return mService.isAdminActive(admin, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -856,7 +855,7 @@
             try {
                 return mService.isRemovingAdmin(admin, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -881,7 +880,7 @@
             try {
                 return mService.getActiveAdmins(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -897,7 +896,7 @@
             try {
                 return mService.packageHasActiveAdmins(packageName, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -914,7 +913,7 @@
             try {
                 mService.removeActiveAdmin(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -933,7 +932,7 @@
             try {
                 return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -1034,7 +1033,7 @@
             try {
                 mService.setPasswordQuality(admin, quality);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1055,7 +1054,7 @@
             try {
                 return mService.getPasswordQuality(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return PASSWORD_QUALITY_UNSPECIFIED;
@@ -1087,7 +1086,7 @@
             try {
                 mService.setPasswordMinimumLength(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1108,7 +1107,7 @@
             try {
                 return mService.getPasswordMinimumLength(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1141,7 +1140,7 @@
             try {
                 mService.setPasswordMinimumUpperCase(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1169,7 +1168,7 @@
             try {
                 return mService.getPasswordMinimumUpperCase(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1202,7 +1201,7 @@
             try {
                 mService.setPasswordMinimumLowerCase(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1230,7 +1229,7 @@
             try {
                 return mService.getPasswordMinimumLowerCase(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1262,7 +1261,7 @@
             try {
                 mService.setPasswordMinimumLetters(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1288,7 +1287,7 @@
             try {
                 return mService.getPasswordMinimumLetters(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1320,7 +1319,7 @@
             try {
                 mService.setPasswordMinimumNumeric(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1347,7 +1346,7 @@
             try {
                 return mService.getPasswordMinimumNumeric(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1379,7 +1378,7 @@
             try {
                 mService.setPasswordMinimumSymbols(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1405,7 +1404,7 @@
             try {
                 return mService.getPasswordMinimumSymbols(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1437,7 +1436,7 @@
             try {
                 mService.setPasswordMinimumNonLetter(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1464,7 +1463,7 @@
             try {
                 return mService.getPasswordMinimumNonLetter(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1497,7 +1496,7 @@
             try {
                 mService.setPasswordHistoryLength(admin, length);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1529,7 +1528,7 @@
             try {
                 mService.setPasswordExpirationTimeout(admin, timeout);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1548,7 +1547,7 @@
             try {
                 return mService.getPasswordExpirationTimeout(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1569,7 +1568,7 @@
             try {
                 return mService.getPasswordExpiration(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1592,7 +1591,7 @@
             try {
                 return mService.getPasswordHistoryLength(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1625,7 +1624,7 @@
             try {
                 return mService.isActivePasswordSufficient(myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -1644,7 +1643,7 @@
             try {
                 return mService.getCurrentFailedPasswordAttempts(myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return -1;
@@ -1661,7 +1660,7 @@
             try {
                 return mService.getDoNotAskCredentialsOnBoot();
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed to call getDoNotAskCredentialsOnBoot()", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -1691,7 +1690,7 @@
             try {
                 mService.setMaximumFailedPasswordsForWipe(admin, num);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1713,7 +1712,7 @@
             try {
                 return mService.getMaximumFailedPasswordsForWipe(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1731,7 +1730,7 @@
             try {
                 return mService.getProfileWithMinimumFailedPasswordsForWipe(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return UserHandle.USER_NULL;
@@ -1796,7 +1795,7 @@
             try {
                 return mService.resetPassword(password, flags);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -1820,7 +1819,7 @@
             try {
                 mService.setMaximumTimeToLock(admin, timeMs);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1843,7 +1842,7 @@
             try {
                 return mService.getMaximumTimeToLock(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -1862,7 +1861,7 @@
             try {
                 mService.lockNow();
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1899,7 +1898,7 @@
             try {
                 mService.wipeData(flags);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -1969,7 +1968,7 @@
                 }
                 return mService.setGlobalProxy(admin, hostSpec, exclSpec);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -1997,7 +1996,7 @@
             try {
                 mService.setRecommendedGlobalProxy(admin, proxyInfo);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2013,7 +2012,7 @@
             try {
                 return mService.getGlobalProxyAdmin(myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -2143,7 +2142,7 @@
             try {
                 return mService.setStorageEncryption(admin, encrypt);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2163,7 +2162,7 @@
             try {
                 return mService.getStorageEncryption(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -2198,7 +2197,7 @@
             try {
                 return mService.getStorageEncryptionStatus(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2219,7 +2218,7 @@
             try {
                 return mService.installCaCert(admin, certBuffer);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -2240,7 +2239,7 @@
             } catch (CertificateException e) {
                 Log.w(TAG, "Unable to parse certificate", e);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2268,7 +2267,7 @@
                     }
                 }
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed talking with device policy service", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return certs;
@@ -2287,7 +2286,7 @@
                 mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
                         .toArray(new String[0]));
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed talking with device policy service", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -2305,7 +2304,7 @@
                 mService.enforceCanManageCaCerts(admin);
                 return getCaCertAlias(certBuffer) != null;
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed talking with device policy service", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             } catch (CertificateException ce) {
                 Log.w(TAG, "Could not parse certificate", ce);
             }
@@ -2333,7 +2332,7 @@
                     .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
             return mService.installKeyPair(admin, pkcs8Key, pemCert, alias);
         } catch (RemoteException e) {
-            Log.w(TAG, "Failed talking with device policy service", e);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
         } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
             Log.w(TAG, "Failed to obtain private key material", e);
         } catch (CertificateException | IOException e) {
@@ -2391,14 +2390,14 @@
             try {
                 mService.setCertInstallerPackage(admin, installerPackage);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
 
     /**
      * Called by a profile owner or device owner to retrieve the certificate installer for the
-     * current user. null if none is set.
+     * user. null if none is set.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return The package name of the current delegated certificate installer, or {@code null}
@@ -2409,7 +2408,7 @@
             try {
                 return mService.getCertInstallerPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -2434,14 +2433,14 @@
             try {
                 mService.setCameraDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
 
     /**
      * Determine whether or not the device's cameras have been disabled for this user,
-     * either by the current admin, if specified, or all admins.
+     * either by the calling admin, if specified, or all admins.
      * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled the camera
      */
@@ -2455,7 +2454,7 @@
             try {
                 return mService.getCameraDisabled(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -2492,13 +2491,13 @@
             try {
                 mService.setScreenCaptureDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
 
     /**
-     * Determine whether or not screen capture has been disabled by the current
+     * Determine whether or not screen capture has been disabled by the calling
      * admin, if specified, or all admins.
      * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled screen capture.
@@ -2513,7 +2512,7 @@
             try {
                 return mService.getScreenCaptureDisabled(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -2536,7 +2535,7 @@
             try {
                 mService.setAutoTimeRequired(admin, required);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2549,7 +2548,7 @@
             try {
                 return mService.getAutoTimeRequired();
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -2590,13 +2589,13 @@
             try {
                 mService.setKeyguardDisabledFeatures(admin, which);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
 
     /**
-     * Determine whether or not features have been disabled in keyguard either by the current
+     * Determine whether or not features have been disabled in keyguard either by the calling
      * admin, if specified, or all admins.
      * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled features in keyguard.
@@ -2613,7 +2612,7 @@
             try {
                 return mService.getKeyguardDisabledFeatures(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return KEYGUARD_DISABLE_FEATURES_NONE;
@@ -2628,7 +2627,7 @@
             try {
                 mService.setActiveAdmin(policyReceiver, refreshing, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2659,10 +2658,7 @@
 
         try {
             return new DeviceAdminInfo(mContext, ri);
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "Unable to parse device policy " + cn, e);
-            return null;
-        } catch (IOException e) {
+        } catch (XmlPullParserException | IOException e) {
             Log.w(TAG, "Unable to parse device policy " + cn, e);
             return null;
         }
@@ -2676,7 +2672,7 @@
             try {
                 mService.getRemoveWarning(admin, result, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2691,7 +2687,7 @@
                 mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
                         numbers, symbols, nonletter, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2704,7 +2700,7 @@
             try {
                 mService.reportFailedPasswordAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2717,7 +2713,7 @@
             try {
                 mService.reportSuccessfulPasswordAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -2770,7 +2766,7 @@
             try {
                 return mService.setDeviceOwner(who, ownerName, userId);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to set device owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -2852,7 +2848,7 @@
             try {
                 return mService.getDeviceOwnerComponent(callingUserOnly);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return null;
@@ -2871,7 +2867,7 @@
             try {
                 return mService.getDeviceOwnerUserId();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return UserHandle.USER_NULL;
@@ -2891,7 +2887,7 @@
             try {
                 mService.clearDeviceOwner(packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to clear device owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -2933,7 +2929,7 @@
             try {
                 return mService.getDeviceOwnerName();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return null;
@@ -2986,7 +2982,6 @@
                 mService.setActiveAdmin(admin, false, myUserId);
                 return mService.setProfileOwner(admin, ownerName, myUserId);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to set profile owner " + re);
                 throw new IllegalArgumentException("Couldn't set profile owner.", re);
             }
         }
@@ -3008,7 +3003,7 @@
             try {
                 mService.clearProfileOwner(admin);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to clear profile owner " + admin + re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -3022,7 +3017,7 @@
             try {
                 return mService.hasUserSetupCompleted();
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to check whether user setup has completed");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return true;
@@ -3053,7 +3048,7 @@
                 }
                 return mService.setProfileOwner(admin, ownerName, userHandle);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to set profile owner", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
                 throw new IllegalArgumentException("Couldn't set profile owner.", re);
             }
         }
@@ -3076,7 +3071,7 @@
             try {
                 return mService.setDeviceOwnerLockScreenInfo(admin, info);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed talking with device policy service", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -3090,7 +3085,7 @@
             try {
                 return mService.getDeviceOwnerLockScreenInfo();
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed talking with device policy service", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return null;
@@ -3109,7 +3104,7 @@
             try {
                 mService.setProfileEnabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3130,14 +3125,14 @@
             try {
                 mService.setProfileName(admin, profileName);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
 
     /**
      * Used to determine if a particular package is registered as the profile owner for the
-     * current user. A profile owner is a special device admin that has additional privileges
+     * user. A profile owner is a special device admin that has additional privileges
      * within the profile.
      *
      * @param packageName The package name of the app to compare with the registered profile owner.
@@ -3151,7 +3146,7 @@
                 return profileOwner != null
                         && profileOwner.getPackageName().equals(packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to check profile owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -3177,7 +3172,7 @@
             try {
                 return mService.getProfileOwner(userId);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get profile owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
                 throw new IllegalArgumentException(
                         "Requested profile owner for invalid userId", re);
             }
@@ -3196,7 +3191,7 @@
             try {
                 return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get profile owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
                 throw new IllegalArgumentException(
                         "Requested profile owner for invalid userId", re);
             }
@@ -3217,7 +3212,7 @@
             try {
                 return mService.getProfileOwnerName(userId);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get profile owner");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
                 throw new IllegalArgumentException(
                         "Requested profile owner for invalid userId", re);
             }
@@ -3248,7 +3243,7 @@
             try {
                 mService.addPersistentPreferredActivity(admin, filter, activity);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3269,7 +3264,7 @@
             try {
                 mService.clearPackagePersistentPreferredActivities(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3309,7 +3304,7 @@
             try {
                 mService.setApplicationRestrictions(admin, packageName, settings);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3339,7 +3334,7 @@
             try {
                 mService.setTrustAgentConfiguration(admin, target, configuration);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3370,7 +3365,7 @@
             try {
                 return mService.getTrustAgentConfiguration(admin, agent, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return new ArrayList<PersistableBundle>(); // empty list
@@ -3391,7 +3386,7 @@
             try {
                 mService.setCrossProfileCallerIdDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3410,7 +3405,7 @@
             try {
                 return mService.getCrossProfileCallerIdDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -3427,14 +3422,14 @@
             try {
                 return mService.getCrossProfileCallerIdDisabledForUser(userHandle.getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
     }
 
     /**
-     * Start Quick Contact on the managed profile for the current user, if the policy allows.
+     * Start Quick Contact on the managed profile for the user, if the policy allows.
      * @hide
      */
     public void startManagedQuickContact(String actualLookupKey, long actualContactId,
@@ -3444,13 +3439,13 @@
                 mService.startManagedQuickContact(
                         actualLookupKey, actualContactId, directoryId, originalIntent);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
 
     /**
-     * Start Quick Contact on the managed profile for the current user, if the policy allows.
+     * Start Quick Contact on the managed profile for the user, if the policy allows.
      * @hide
      */
     public void startManagedQuickContact(String actualLookupKey, long actualContactId,
@@ -3478,7 +3473,7 @@
             try {
                 mService.setBluetoothContactSharingDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3500,7 +3495,7 @@
             try {
                 return mService.getBluetoothContactSharingDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return true;
@@ -3520,7 +3515,7 @@
                 return mService.getBluetoothContactSharingDisabledForUser(userHandle
                         .getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return true;
@@ -3542,7 +3537,7 @@
             try {
                 mService.addCrossProfileIntentFilter(admin, filter, flags);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3558,7 +3553,7 @@
             try {
                 mService.clearCrossProfileIntentFilters(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3590,7 +3585,7 @@
             try {
                 return mService.setPermittedAccessibilityServices(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -3610,7 +3605,7 @@
             try {
                 return mService.getPermittedAccessibilityServices(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -3634,7 +3629,7 @@
             try {
                 return mService.getPermittedAccessibilityServicesForUser(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -3668,7 +3663,7 @@
             try {
                 return mService.setPermittedInputMethods(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -3689,7 +3684,7 @@
             try {
                 return mService.getPermittedInputMethods(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -3697,7 +3692,7 @@
 
     /**
      * Returns the list of input methods permitted by the device or profiles
-     * owners of the current user.
+     * owners of the current user.  (*Not* calling user, due to a limitation in InputMethodManager.)
      *
      * <p>Null means all input methods are allowed, if a non-null list is returned
      * it will contain the intersection of the permitted lists for any device or profile
@@ -3712,7 +3707,7 @@
             try {
                 return mService.getPermittedInputMethodsForCurrentUser();
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -3732,7 +3727,7 @@
             try {
                 return mService.getKeepUninstalledPackages(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -3755,7 +3750,7 @@
             try {
                 mService.setKeepUninstalledPackages(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3779,7 +3774,7 @@
         try {
             return mService.createUser(admin, name);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not create a user", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
         }
         return null;
     }
@@ -3818,7 +3813,7 @@
             return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
                     adminExtras);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not create a user", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
         }
         return null;
     }
@@ -3835,7 +3830,7 @@
         try {
             return mService.removeUser(admin, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not remove user ", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -3853,7 +3848,7 @@
         try {
             return mService.switchUser(admin, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not switch user ", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -3876,7 +3871,7 @@
             try {
                 return mService.getApplicationRestrictions(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -3898,7 +3893,7 @@
             try {
                 mService.setUserRestriction(admin, key, true);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3919,7 +3914,7 @@
             try {
                 mService.setUserRestriction(admin, key, false);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -3946,7 +3941,7 @@
             try {
                 ret = mService.getUserRestrictions(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return ret == null ? new Bundle() : ret;
@@ -3968,7 +3963,7 @@
             try {
                 return mService.setApplicationHidden(admin, packageName, hidden);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -3986,7 +3981,7 @@
             try {
                 return mService.isApplicationHidden(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -3997,14 +3992,14 @@
      * when the user was initialized.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param packageName The package to be re-enabled in the current profile.
+     * @param packageName The package to be re-enabled in the calling profile.
      */
     public void enableSystemApp(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 mService.enableSystemApp(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed to install package: " + packageName);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -4015,7 +4010,7 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param intent An intent matching the app(s) to be installed. All apps that resolve for this
-     *               intent will be re-enabled in the current profile.
+     *               intent will be re-enabled in the calling profile.
      * @return int The number of activities that matched the intent and were installed.
      */
     public int enableSystemApp(@NonNull ComponentName admin, Intent intent) {
@@ -4023,7 +4018,7 @@
             try {
                 return mService.enableSystemAppWithIntent(admin, intent);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed to install packages matching filter: " + intent);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return 0;
@@ -4050,7 +4045,7 @@
             try {
                 mService.setAccountManagementDisabled(admin, accountType, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -4078,7 +4073,7 @@
             try {
                 return mService.getAccountTypesWithManagementDisabledAsUser(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
 
@@ -4109,7 +4104,7 @@
             try {
                 mService.setLockTaskPackages(admin, packages);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -4125,7 +4120,7 @@
             try {
                 return mService.getLockTaskPackages(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return null;
@@ -4141,7 +4136,7 @@
             try {
                 return mService.isLockTaskPermitted(pkg);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
         return false;
@@ -4188,7 +4183,7 @@
             try {
                 mService.setGlobalSetting(admin, setting, value);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -4216,7 +4211,7 @@
             try {
                 mService.setSecureSetting(admin, setting, value);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with device policy service", e);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
         }
     }
@@ -4237,7 +4232,7 @@
             try {
                 mService.setRestrictionsProvider(admin, provider);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to set permission provider on device policy service");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -4253,7 +4248,7 @@
             try {
                 mService.setMasterVolumeMuted(admin, on);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to setMasterMute on device policy service");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -4269,7 +4264,7 @@
             try {
                 return mService.isMasterVolumeMuted(admin);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get isMasterMute on device policy service");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -4289,13 +4284,13 @@
             try {
                 mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to call block uninstall on device policy service");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
 
     /**
-     * Check whether the current user has been blocked by device policy from uninstalling a package.
+     * Check whether the user has been blocked by device policy from uninstalling a package.
      * Requires the caller to be the profile owner if checking a specific admin's policy.
      * <p>
      * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the
@@ -4313,7 +4308,7 @@
             try {
                 return mService.isUninstallBlocked(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to call block uninstall on device policy service");
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -4341,7 +4336,7 @@
             try {
                 return mService.addCrossProfileWidgetProvider(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, "Error calling addCrossProfileWidgetProvider", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -4368,7 +4363,7 @@
             try {
                 return mService.removeCrossProfileWidgetProvider(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, "Error calling removeCrossProfileWidgetProvider", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return false;
@@ -4392,14 +4387,14 @@
                     return providers;
                 }
             } catch (RemoteException re) {
-                Log.w(TAG, "Error calling getCrossProfileWidgetProviders", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return Collections.emptyList();
     }
 
     /**
-     * Called by profile or device owners to set the current user's photo.
+     * Called by profile or device owners to set the user's photo.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param icon the bitmap to set as the photo.
@@ -4408,7 +4403,7 @@
         try {
             mService.setUserIcon(admin, icon);
         } catch (RemoteException re) {
-            Log.w(TAG, "Could not set the user icon ", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
         }
     }
 
@@ -4428,7 +4423,7 @@
             try {
                 mService.setSystemUpdatePolicy(admin, policy);
             } catch (RemoteException re) {
-                Log.w(TAG, "Error calling setSystemUpdatePolicy", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -4443,7 +4438,7 @@
             try {
                 return mService.getSystemUpdatePolicy();
             } catch (RemoteException re) {
-                Log.w(TAG, "Error calling getSystemUpdatePolicy", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
         return null;
@@ -4467,7 +4462,7 @@
         try {
             return mService.setKeyguardDisabled(admin, disabled);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -4487,7 +4482,7 @@
         try {
             return mService.setStatusBarDisabled(admin, disabled);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -4507,7 +4502,7 @@
             try {
                 mService.notifyPendingSystemUpdate(updateReceivedTime);
             } catch (RemoteException re) {
-                Log.w(TAG, "Could not notify device owner about pending system update", re);
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             }
         }
     }
@@ -4533,7 +4528,7 @@
         try {
             mService.setPermissionPolicy(admin, policy);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
         }
     }
 
@@ -4584,7 +4579,7 @@
         try {
             return mService.setPermissionGrantState(admin, packageName, permission, grantState);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -4611,7 +4606,7 @@
         try {
             return mService.getPermissionGrantState(admin, packageName, permission);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return PERMISSION_GRANT_STATE_DEFAULT;
         }
     }
@@ -4630,7 +4625,7 @@
         try {
             return mService.isProvisioningAllowed(action);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -4647,7 +4642,7 @@
         try {
             return mService.isManagedProfile(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -4663,7 +4658,7 @@
         try {
             return mService.isSystemOnlyUser(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return false;
         }
     }
@@ -4680,7 +4675,7 @@
         try {
             return mService.getWifiMacAddress();
         } catch (RemoteException re) {
-            Log.w(TAG, "Failed talking with device policy service", re);
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
             return null;
         }
     }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 3e8a51e..eb4cb91 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2165,7 +2165,7 @@
     @Deprecated
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
-        if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
+        if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
         if (callback == null) {
             if (DBG) Log.e(TAG, "startLeScan: null callback");
             return false;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index 7b5a045..1fb7825 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -172,8 +172,12 @@
     }
 
     public String toString() {
+        return toString(false);
+    }
+
+    public String toString(boolean loggable) {
         StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
-        builder.append(mDevice);
+        builder.append(loggable ? mDevice.hashCode() : mDevice);
         builder.append(", mId: ");
         builder.append(mId);
         builder.append(", mState: ");
@@ -189,7 +193,7 @@
             default: builder.append(mState); break;
         }
         builder.append(", mNumber: ");
-        builder.append(mNumber);
+        builder.append(loggable ? mNumber.hashCode() : mNumber);
         builder.append(", mMultiParty: ");
         builder.append(mMultiParty);
         builder.append(", mOutgoing: ");
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index fb81fd1..ae12c88 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -27,6 +27,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Arrays;
 import java.util.Locale;
 import java.util.UUID;
 import android.net.LocalSocket;
@@ -234,9 +235,9 @@
         BluetoothSocket as = new BluetoothSocket(this);
         as.mSocketState = SocketState.CONNECTED;
         FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
-        if (DBG) Log.d(TAG, "socket fd passed by stack  fds: " + fds);
+        if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + Arrays.toString(fds));
         if(fds == null || fds.length != 1) {
-            Log.e(TAG, "socket fd passed from stack failed, fds: " + fds);
+            Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
             as.close();
             throw new IOException("bt socket acept failed");
         }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index ba9cf7c..1c3f45c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -52,6 +52,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * Content providers are one of the primary building blocks of Android applications, providing
@@ -1854,7 +1855,7 @@
             if (mAuthority != null) {
                 message += mAuthority;
             } else {
-                message += mAuthorities;
+                message += Arrays.toString(mAuthorities);
             }
             throw new SecurityException(message);
         }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1f7fd9d..38a4475 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -53,8 +53,8 @@
 import android.os.UserManager;
 import android.provider.MediaStore;
 import android.util.AttributeSet;
-import android.view.DisplayAdjustments;
 import android.view.Display;
+import android.view.DisplayAdjustments;
 import android.view.ViewDebug;
 import android.view.WindowManager;
 
@@ -2116,6 +2116,14 @@
             UserHandle user);
 
     /**
+     * @hide
+     * This is just here for sending CONNECTIVITY_ACTION.
+     */
+    @Deprecated
+    public abstract void sendStickyBroadcastAsUser(@RequiresPermission Intent intent,
+            UserHandle user, Bundle options);
+
+    /**
      * <p>Version of
      * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)}
      * that allows you to specify the
@@ -3870,7 +3878,7 @@
      *
      * @hide
      */
-    public static final int CONTEXT_STORAGE_DEVICE_ENCRYPTED = 0x00000008;
+    public static final int CONTEXT_DEVICE_ENCRYPTED_STORAGE = 0x00000008;
 
     /**
      * Flag for use with {@link #createPackageContext}: point all file APIs at
@@ -3878,11 +3886,7 @@
      *
      * @hide
      */
-    public static final int CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED = 0x00000010;
-
-    /** {@hide} */
-    public static final int CONTEXT_STORAGE_MASK = CONTEXT_STORAGE_DEVICE_ENCRYPTED
-            | CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED;
+    public static final int CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE = 0x00000010;
 
     /**
      * @hide Used to indicate we should tell the activity manager about the process
@@ -3987,19 +3991,23 @@
      * Return a new Context object for the current Context but whose storage
      * APIs are backed by device-encrypted storage.
      * <p>
-     * Data stored in device-encrypted storage is typically encrypted with a
-     * key tied to the physical device, and they can be accessed whenever the
-     * device has booted successfully, both <em>before and after</em> the user
-     * has entered their credentials (such as a lock pattern or PIN).
+     * Data stored in device-encrypted storage is typically encrypted with a key
+     * tied to the physical device, and it can be accessed when the device has
+     * booted successfully, both <em>before and after</em> the user has
+     * authenticated with their credentials (such as a lock pattern or PIN).
+     * Because device-encrypted data is available before user authentication,
+     * you should carefully consider what data you store using this Context.
      * <p>
      * Each call to this method returns a new instance of a Context object;
      * Context objects are not shared, however common state (ClassLoader, other
      * Resources for the same configuration) may be so the Context itself can be
      * fairly lightweight.
      *
-     * @see #isDeviceEncrypted()
+     * @return new Context or {@code null} if device-encrypted storage is not
+     *         supported or available on this device.
+     * @see #isDeviceEncryptedStorage()
      */
-    public abstract Context createDeviceEncryptedContext(Context context);
+    public abstract Context createDeviceEncryptedStorageContext();
 
     /**
      * Return a new Context object for the current Context but whose storage
@@ -4015,9 +4023,11 @@
      * Resources for the same configuration) may be so the Context itself can be
      * fairly lightweight.
      *
-     * @see #isCredentialEncrypted()
+     * @see #isCredentialEncryptedStorage()
+     * @hide
      */
-    public abstract Context createCredentialEncryptedContext(Context context);
+    @SystemApi
+    public abstract Context createCredentialEncryptedStorageContext();
 
     /**
      * Gets the display adjustments holder for this context.  This information
@@ -4045,15 +4055,17 @@
      * Indicates if the storage APIs of this Context are backed by
      * device-encrypted storage.
      *
-     * @see #createDeviceEncryptedContext(Context)
+     * @see #createDeviceEncryptedStorageContext()
      */
-    public abstract boolean isDeviceEncrypted();
+    public abstract boolean isDeviceEncryptedStorage();
 
     /**
      * Indicates if the storage APIs of this Context are backed by
      * credential-encrypted storage.
      *
-     * @see #createCredentialEncryptedContext(Context)
+     * @see #createCredentialEncryptedStorageContext()
+     * @hide
      */
-    public abstract boolean isCredentialEncrypted();
+    @SystemApi
+    public abstract boolean isCredentialEncryptedStorage();
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 73d0ddc..1a3d262 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -536,6 +536,13 @@
         mBase.sendStickyBroadcastAsUser(intent, user);
     }
 
+    /** @hide */
+    @Override
+    @Deprecated
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+        mBase.sendStickyBroadcastAsUser(intent, user, options);
+    }
+
     @Override
     @Deprecated
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
@@ -792,22 +799,26 @@
     }
 
     @Override
-    public Context createDeviceEncryptedContext(Context context) {
-        return mBase.createDeviceEncryptedContext(context);
+    public Context createDeviceEncryptedStorageContext() {
+        return mBase.createDeviceEncryptedStorageContext();
+    }
+
+    /** {@hide} */
+    @SystemApi
+    @Override
+    public Context createCredentialEncryptedStorageContext() {
+        return mBase.createCredentialEncryptedStorageContext();
     }
 
     @Override
-    public Context createCredentialEncryptedContext(Context context) {
-        return mBase.createCredentialEncryptedContext(context);
+    public boolean isDeviceEncryptedStorage() {
+        return mBase.isDeviceEncryptedStorage();
     }
 
+    /** {@hide} */
+    @SystemApi
     @Override
-    public boolean isDeviceEncrypted() {
-        return mBase.isDeviceEncrypted();
-    }
-
-    @Override
-    public boolean isCredentialEncrypted() {
-        return mBase.isCredentialEncrypted();
+    public boolean isCredentialEncryptedStorage() {
+        return mBase.isCredentialEncryptedStorage();
     }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bc7620c..a27d1cb 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4471,6 +4471,22 @@
      * @hide
      */
     public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
+    /**
+     * If set, the broadcast will always go to manifest receivers in background (cached
+     * or not running) apps, regardless of whether that would be done by default.  By
+     * default they will only receive broadcasts if the broadcast has specified an
+     * explicit component or package name.
+     * @hide
+     */
+    public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
+    /**
+     * If set, the broadcast will never go to manifest receivers in background (cached
+     * or not running) apps, regardless of whether that would be done by default.  By
+     * default they will receive broadcasts if the broadcast has specified an
+     * explicit component or package name.
+     * @hide
+     */
+    public static final int FLAG_RECEIVER_EXCLUDE_BACKGROUND = 0x00800000;
 
     /**
      * @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4a3c59b..0cb0e9f 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -756,13 +756,20 @@
     }
 
     public void dump(Printer pw, String prefix) {
+        dump(pw, prefix, DUMP_FLAG_ALL);
+    }
+
+    /** @hide */
+    public void dump(Printer pw, String prefix, int flags) {
         super.dumpFront(pw, prefix);
         if (permission != null) {
             pw.println(prefix + "permission=" + permission);
         }
-        pw.println(prefix + "taskAffinity=" + taskAffinity
-                + " targetActivity=" + targetActivity
-                + " persistableMode=" + persistableModeToString());
+        if ((flags&DUMP_FLAG_DETAILS) != 0) {
+            pw.println(prefix + "taskAffinity=" + taskAffinity
+                    + " targetActivity=" + targetActivity
+                    + " persistableMode=" + persistableModeToString());
+        }
         if (launchMode != 0 || flags != 0 || theme != 0) {
             pw.println(prefix + "launchMode=" + launchMode
                     + " flags=0x" + Integer.toHexString(flags)
@@ -777,14 +784,17 @@
         if (uiOptions != 0) {
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
-        pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
-        pw.println(prefix + "lockTaskLaunchMode=" + lockTaskLaunchModeToString(lockTaskLaunchMode));
+        if ((flags&DUMP_FLAG_DETAILS) != 0) {
+            pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
+            pw.println(prefix + "lockTaskLaunchMode="
+                    + lockTaskLaunchModeToString(lockTaskLaunchMode));
+        }
         if (layout != null) {
             pw.println(prefix + "initialLayout=" + layout.width + "|"
                     + layout.widthFraction + ", " + layout.height + "|"
                     + layout.heightFraction + ", " + layout.gravity);
         }
-        super.dumpBack(pw, prefix);
+        super.dumpBack(pw, prefix, flags);
     }
 
     public String toString() {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 4c5e766..1eeace1 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -486,13 +486,6 @@
     public static final int PRIVATE_FLAG_AUTOPLAY = 1 << 7;
 
     /**
-     * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
-     * and for most purposes is considered as not installed.
-     * {@hide}
-     */
-    public static final int PRIVATE_FLAG_EPHEMERAL = 1<<8;
-
-    /**
      * When set, at least one component inside this application is encryption aware.
      *
      * @hide
@@ -500,6 +493,13 @@
     public static final int PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE = 1 << 8;
 
     /**
+     * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
+     * and for most purposes is considered as not installed.
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 9;
+
+    /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * {@hide}
      */
@@ -710,21 +710,30 @@
     public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
 
     public void dump(Printer pw, String prefix) {
+        dump(pw, prefix, DUMP_FLAG_ALL);
+    }
+
+    /** @hide */
+    public void dump(Printer pw, String prefix, int flags) {
         super.dumpFront(pw, prefix);
-        if (className != null) {
+        if ((flags&DUMP_FLAG_DETAILS) != 0 && className != null) {
             pw.println(prefix + "className=" + className);
         }
         if (permission != null) {
             pw.println(prefix + "permission=" + permission);
         }
         pw.println(prefix + "processName=" + processName);
-        pw.println(prefix + "taskAffinity=" + taskAffinity);
+        if ((flags&DUMP_FLAG_DETAILS) != 0) {
+            pw.println(prefix + "taskAffinity=" + taskAffinity);
+        }
         pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
                 + " privateFlags=0x" + Integer.toHexString(privateFlags)
                 + " theme=0x" + Integer.toHexString(theme));
-        pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
-                + " compatibleWidthLimitDp=" + compatibleWidthLimitDp
-                + " largestWidthLimitDp=" + largestWidthLimitDp);
+        if ((flags&DUMP_FLAG_DETAILS) != 0) {
+            pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
+                    + " compatibleWidthLimitDp=" + compatibleWidthLimitDp
+                    + " largestWidthLimitDp=" + largestWidthLimitDp);
+        }
         pw.println(prefix + "sourceDir=" + sourceDir);
         if (!Objects.equals(sourceDir, publicSourceDir)) {
             pw.println(prefix + "publicSourceDir=" + publicSourceDir);
@@ -737,33 +746,38 @@
             pw.println(prefix + "splitPublicSourceDirs=" + Arrays.toString(splitPublicSourceDirs));
         }
         if (resourceDirs != null) {
-            pw.println(prefix + "resourceDirs=" + resourceDirs);
+            pw.println(prefix + "resourceDirs=" + Arrays.toString(resourceDirs));
         }
-        if (seinfo != null) {
+        if ((flags&DUMP_FLAG_DETAILS) != 0 && seinfo != null) {
             pw.println(prefix + "seinfo=" + seinfo);
         }
         pw.println(prefix + "dataDir=" + dataDir);
-        pw.println(prefix + "deviceEncryptedDataDir=" + deviceEncryptedDataDir);
-        pw.println(prefix + "credentialEncryptedDataDir=" + credentialEncryptedDataDir);
-        if (sharedLibraryFiles != null) {
-            pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
+        if ((flags&DUMP_FLAG_DETAILS) != 0) {
+            pw.println(prefix + "deviceEncryptedDataDir=" + deviceEncryptedDataDir);
+            pw.println(prefix + "credentialEncryptedDataDir=" + credentialEncryptedDataDir);
+            if (sharedLibraryFiles != null) {
+                pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
+            }
         }
         pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion
                 + " versionCode=" + versionCode);
-        if (manageSpaceActivityName != null) {
-            pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
-        }
-        if (descriptionRes != 0) {
-            pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
-        }
-        if (uiOptions != 0) {
-            pw.println(prefix + "uiOptions=0x" + Integer.toHexString(uiOptions));
-        }
-        pw.println(prefix + "supportsRtl=" + (hasRtlSupport() ? "true" : "false"));
-        if (fullBackupContent > 0) {
-            pw.println(prefix + "fullBackupContent=@xml/" + fullBackupContent);
-        } else {
-            pw.println(prefix + "fullBackupContent=" + (fullBackupContent < 0 ? "false" : "true"));
+        if ((flags&DUMP_FLAG_DETAILS) != 0) {
+            if (manageSpaceActivityName != null) {
+                pw.println(prefix + "manageSpaceActivityName=" + manageSpaceActivityName);
+            }
+            if (descriptionRes != 0) {
+                pw.println(prefix + "description=0x" + Integer.toHexString(descriptionRes));
+            }
+            if (uiOptions != 0) {
+                pw.println(prefix + "uiOptions=0x" + Integer.toHexString(uiOptions));
+            }
+            pw.println(prefix + "supportsRtl=" + (hasRtlSupport() ? "true" : "false"));
+            if (fullBackupContent > 0) {
+                pw.println(prefix + "fullBackupContent=@xml/" + fullBackupContent);
+            } else {
+                pw.println(prefix + "fullBackupContent="
+                        + (fullBackupContent < 0 ? "false" : "true"));
+            }
         }
         super.dumpBack(pw, prefix);
     }
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index ad7ebe5..a295cc5 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -150,23 +150,32 @@
 
     protected void dumpFront(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
+        if (processName != null && !packageName.equals(processName)) {
+            pw.println(prefix + "processName=" + processName);
+        }
         pw.println(prefix + "enabled=" + enabled + " exported=" + exported
-                + " encryptionAware=" + encryptionAware + " processName=" + processName);
+                + " encryptionAware=" + encryptionAware);
         if (descriptionRes != 0) {
             pw.println(prefix + "description=" + descriptionRes);
         }
     }
-    
+
     protected void dumpBack(Printer pw, String prefix) {
-        if (applicationInfo != null) {
-            pw.println(prefix + "ApplicationInfo:");
-            applicationInfo.dump(pw, prefix + "  ");
-        } else {
-            pw.println(prefix + "ApplicationInfo: null");
+        dumpBack(pw, prefix, DUMP_FLAG_ALL);
+    }
+    
+    void dumpBack(Printer pw, String prefix, int flags) {
+        if ((flags&DUMP_FLAG_APPLICATION) != 0) {
+            if (applicationInfo != null) {
+                pw.println(prefix + "ApplicationInfo:");
+                applicationInfo.dump(pw, prefix + "  ", flags);
+            } else {
+                pw.println(prefix + "ApplicationInfo: null");
+            }
         }
         super.dumpBack(pw, prefix);
     }
-    
+
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         super.writeToParcel(dest, parcelableFlags);
         if ((parcelableFlags & Parcelable.PARCELABLE_ELIDE_DUPLICATES) != 0) {
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 22a899c..4df83036 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -282,6 +282,21 @@
         return null;
     }
 
+    /**
+     * @hide Flag for dumping: include all details.
+     */
+    public static final int DUMP_FLAG_DETAILS = 1<<0;
+
+    /**
+     * @hide Flag for dumping: include nested ApplicationInfo.
+     */
+    public static final int DUMP_FLAG_APPLICATION = 1<<1;
+
+    /**
+     * @hide Flag for dumping: all flags to dump everything.
+     */
+    public static final int DUMP_FLAG_ALL = DUMP_FLAG_DETAILS | DUMP_FLAG_APPLICATION;
+
     protected void dumpFront(Printer pw, String prefix) {
         if (name != null) {
             pw.println(prefix + "name=" + name);
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index f6ea058..7e7b32f 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -115,9 +115,15 @@
     }
 
     public void dump(Printer pw, String prefix) {
+        dump(pw, prefix, DUMP_FLAG_ALL);
+    }
+
+    /** @hide */
+    public void dump(Printer pw, String prefix, int flags) {
         super.dumpFront(pw, prefix);
         pw.println(prefix + "authority=" + authority);
         pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
+        super.dumpBack(pw, prefix, flags);
     }
 
     public int describeContents() {
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 7bab35c..a5fb451 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -260,6 +260,11 @@
     }
 
     public void dump(Printer pw, String prefix) {
+        dump(pw, prefix, PackageItemInfo.DUMP_FLAG_ALL);
+    }
+
+    /** @hide */
+    public void dump(Printer pw, String prefix, int flags) {
         if (filter != null) {
             pw.println(prefix + "Filter:");
             filter.dump(pw, prefix + "  ");
@@ -279,16 +284,16 @@
         }
         if (activityInfo != null) {
             pw.println(prefix + "ActivityInfo:");
-            activityInfo.dump(pw, prefix + "  ");
+            activityInfo.dump(pw, prefix + "  ", flags);
         } else if (serviceInfo != null) {
             pw.println(prefix + "ServiceInfo:");
-            serviceInfo.dump(pw, prefix + "  ");
+            serviceInfo.dump(pw, prefix + "  ", flags);
         } else if (providerInfo != null) {
             pw.println(prefix + "ProviderInfo:");
-            providerInfo.dump(pw, prefix + "  ");
+            providerInfo.dump(pw, prefix + "  ", flags);
         }
     }
-    
+
     public ResolveInfo() {
         targetUserId = UserHandle.USER_CURRENT;
     }
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 796c2a4..74e5c2a 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -74,9 +74,15 @@
     }
 
     public void dump(Printer pw, String prefix) {
+        dump(pw, prefix, DUMP_FLAG_ALL);
+    }
+
+    /** @hide */
+    void dump(Printer pw, String prefix, int flags) {
         super.dumpFront(pw, prefix);
         pw.println(prefix + "permission=" + permission);
         pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
+        super.dumpBack(pw, prefix, flags);
     }
     
     public String toString() {
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 3cda39a..a762f59 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -26,6 +26,7 @@
 import android.os.CancellationSignal;
 import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
+import android.os.Trace;
 import android.util.Log;
 import android.util.LruCache;
 import android.util.Printer;
@@ -1330,6 +1331,10 @@
                     }
                 }
                 operation.mCookie = newOperationCookieLocked(index);
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_DATABASE)) {
+                    Trace.asyncTraceBegin(Trace.TRACE_TAG_DATABASE, operation.getTraceMethodName(),
+                            operation.mCookie);
+                }
                 mIndex = index;
                 return operation.mCookie;
             }
@@ -1367,6 +1372,10 @@
         private boolean endOperationDeferLogLocked(int cookie) {
             final Operation operation = getOperationLocked(cookie);
             if (operation != null) {
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_DATABASE)) {
+                    Trace.asyncTraceEnd(Trace.TRACE_TAG_DATABASE, operation.getTraceMethodName(),
+                            operation.mCookie);
+                }
                 operation.mEndTime = System.currentTimeMillis();
                 operation.mFinished = true;
                 return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery(
@@ -1439,6 +1448,12 @@
     }
 
     private static final class Operation {
+        // Trim all SQL statements to 256 characters inside the trace marker.
+        // This limit gives plenty of context while leaving space for other
+        // entries in the trace buffer (and ensures atrace doesn't truncate the
+        // marker for us, potentially losing metadata in the process).
+        private static final int MAX_TRACE_METHOD_NAME_LEN = 256;
+
         public long mStartTime;
         public long mEndTime;
         public String mKind;
@@ -1492,6 +1507,13 @@
             return mException != null ? "failed" : "succeeded";
         }
 
+        private String getTraceMethodName() {
+            String methodName = mKind + " " + mSql;
+            if (methodName.length() > MAX_TRACE_METHOD_NAME_LEN)
+                return methodName.substring(0, MAX_TRACE_METHOD_NAME_LEN);
+            return methodName;
+        }
+
         private String getFormattedStartTime() {
             // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, and is
             //       relatively expensive to create during preloading. This method is only used
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8a87bff..02d4e59 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -47,6 +47,8 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 
+import static android.system.OsConstants.*;
+
 /**
  * The Camera class is used to set image capture settings, start/stop preview,
  * snap pictures, and retrieve frames for encoding for video.  This class is a
@@ -173,13 +175,6 @@
     private final Object mAutoFocusCallbackLock = new Object();
 
     private static final int NO_ERROR = 0;
-    private static final int EACCESS = -13;
-    private static final int ENODEV = -19;
-    private static final int EBUSY = -16;
-    private static final int EINVAL = -22;
-    private static final int ENOSYS = -38;
-    private static final int EUSERS = -87;
-    private static final int EOPNOTSUPP = -95;
 
     /**
      * Broadcast Action:  A new picture is taken by the camera, and the entry of
@@ -415,30 +410,28 @@
     private Camera(int cameraId, int halVersion) {
         int err = cameraInitVersion(cameraId, halVersion);
         if (checkInitErrors(err)) {
-            switch(err) {
-                case EACCESS:
-                    throw new RuntimeException("Fail to connect to camera service");
-                case ENODEV:
-                    throw new RuntimeException("Camera initialization failed");
-                case ENOSYS:
-                    throw new RuntimeException("Camera initialization failed because some methods"
-                            + " are not implemented");
-                case EOPNOTSUPP:
-                    throw new RuntimeException("Camera initialization failed because the hal"
-                            + " version is not supported by this device");
-                case EINVAL:
-                    throw new RuntimeException("Camera initialization failed because the input"
-                            + " arugments are invalid");
-                case EBUSY:
-                    throw new RuntimeException("Camera initialization failed because the camera"
-                            + " device was already opened");
-                case EUSERS:
-                    throw new RuntimeException("Camera initialization failed because the max"
-                            + " number of camera devices were already opened");
-                default:
-                    // Should never hit this.
-                    throw new RuntimeException("Unknown camera error");
+            if (err == -EACCES) {
+                throw new RuntimeException("Fail to connect to camera service");
+            } else if (err == -ENODEV) {
+                throw new RuntimeException("Camera initialization failed");
+            } else if (err == -ENOSYS) {
+                throw new RuntimeException("Camera initialization failed because some methods"
+                        + " are not implemented");
+            } else if (err == -EOPNOTSUPP) {
+                throw new RuntimeException("Camera initialization failed because the hal"
+                        + " version is not supported by this device");
+            } else if (err == -EINVAL) {
+                throw new RuntimeException("Camera initialization failed because the input"
+                        + " arugments are invalid");
+            } else if (err == -EBUSY) {
+                throw new RuntimeException("Camera initialization failed because the camera"
+                        + " device was already opened");
+            } else if (err == -EUSERS) {
+                throw new RuntimeException("Camera initialization failed because the max"
+                        + " number of camera devices were already opened");
             }
+            // Should never hit this.
+            throw new RuntimeException("Unknown camera error");
         }
     }
 
@@ -490,15 +483,13 @@
     Camera(int cameraId) {
         int err = cameraInitNormal(cameraId);
         if (checkInitErrors(err)) {
-            switch(err) {
-                case EACCESS:
-                    throw new RuntimeException("Fail to connect to camera service");
-                case ENODEV:
-                    throw new RuntimeException("Camera initialization failed");
-                default:
-                    // Should never hit this.
-                    throw new RuntimeException("Unknown camera error");
+            if (err == -EACCES) {
+                throw new RuntimeException("Fail to connect to camera service");
+            } else if (err == -ENODEV) {
+                throw new RuntimeException("Camera initialization failed");
             }
+            // Should never hit this.
+            throw new RuntimeException("Unknown camera error");
         }
     }
 
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 6b8e113..798c941 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -43,6 +43,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.system.OsConstants.EACCES;
+import static android.system.OsConstants.ENODEV;
+
 /**
  * Compatibility implementation of the Camera2 API binder interface.
  *
@@ -88,6 +91,14 @@
         mSurfaceIdCounter = 0;
     }
 
+    private static int translateErrorsFromCamera1(int errorCode) {
+        if (errorCode == -EACCES) {
+            return CameraBinderDecorator.PERMISSION_DENIED;
+        }
+
+        return errorCode;
+    }
+
     /**
      * Create a separate looper/thread for the camera to run on; open the camera.
      *
@@ -382,7 +393,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot submit request, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -402,7 +413,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot submit request list, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -421,7 +432,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot cancel request, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -442,7 +453,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot begin configure, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -462,7 +473,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot end configure, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         ArrayList<Surface> surfaces = null;
@@ -490,7 +501,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot delete stream, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -515,7 +526,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot create stream, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -552,7 +563,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot create default request, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         CameraMetadataNative template;
@@ -585,7 +596,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot wait until idle, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -605,7 +616,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot flush, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         synchronized(mConfigureLock) {
@@ -627,7 +638,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot prepare stream, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         // LEGACY doesn't support actual prepare, just signal success right away
@@ -647,7 +658,7 @@
         }
         if (mLegacyDevice.isClosed()) {
             Log.e(TAG, "Cannot tear down stream, device has been closed.");
-            return CameraBinderDecorator.ENODEV;
+            return -ENODEV;
         }
 
         // LEGACY doesn't support actual teardown, so just a no-op
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
index 4b7cfbf..4501e81 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
@@ -19,6 +19,8 @@
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.util.AndroidException;
 
+import static android.system.OsConstants.ENODEV;
+
 /**
  * Utility class containing exception handling used solely by the compatibility mode shim.
  */
@@ -51,18 +53,15 @@
      * exceptions.</p>
      *
      * @param errorFlag error to throw as an exception.
-     * @throws {@link BufferQueueAbandonedException} for {@link CameraBinderDecorator#ENODEV}.
+     * @throws {@link BufferQueueAbandonedException} for -ENODEV.
      * @throws {@link UnsupportedOperationException} for an unknown negative error code.
      * @return {@code errorFlag} if the value was non-negative, throws otherwise.
      */
     public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
-        switch (errorFlag) {
-            case CameraBinderDecorator.NO_ERROR: {
-                return CameraBinderDecorator.NO_ERROR;
-            }
-            case CameraBinderDecorator.BAD_VALUE: {
-                throw new BufferQueueAbandonedException();
-            }
+        if (errorFlag == CameraBinderDecorator.NO_ERROR) {
+            return CameraBinderDecorator.NO_ERROR;
+        } else if (errorFlag == -ENODEV) {
+            throw new BufferQueueAbandonedException();
         }
 
         if (errorFlag < 0) {
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index b8d6960..8be49e8 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -834,6 +834,7 @@
      * <ul>
      * <li>{@link ImageFormat#JPEG JPEG}
      * <li>{@link ImageFormat#RAW_SENSOR RAW16}
+     * <li>{@link ImageFormat#RAW_PRIVATE RAW_PRIVATE}
      * </ul>
      * </p>
      *
@@ -1328,9 +1329,7 @@
         SparseIntArray map = getFormatsMap(output);
         for (int j = 0; j < map.size(); j++) {
             int format = map.keyAt(j);
-            if (format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
-                formats[i++] = imageFormatToPublic(format);
-            }
+            formats[i++] = imageFormatToPublic(format);
         }
         if (output) {
             for (int j = 0; j < mDepthOutputFormats.size(); j++) {
@@ -1392,9 +1391,6 @@
     private int getPublicFormatCount(boolean output) {
         SparseIntArray formatsMap = getFormatsMap(output);
         int size = formatsMap.size();
-        if (formatsMap.indexOfKey(HAL_PIXEL_FORMAT_RAW_OPAQUE) >= 0) {
-            size -= 1;
-        }
         if (output) {
             size += mDepthOutputFormats.size();
         }
@@ -1603,6 +1599,8 @@
                 return "Y16";
             case ImageFormat.RAW_SENSOR:
                 return "RAW_SENSOR";
+            case ImageFormat.RAW_PRIVATE:
+                return "RAW_PRIVATE";
             case ImageFormat.RAW10:
                 return "RAW10";
             case ImageFormat.DEPTH16:
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 1aee794..162edc9 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -22,6 +22,7 @@
 import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
 import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
 import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
+import static android.system.OsConstants.*;
 
 import android.os.DeadObjectException;
 import android.os.RemoteException;
@@ -37,12 +38,12 @@
 public class CameraBinderDecorator {
 
     public static final int NO_ERROR = 0;
-    public static final int PERMISSION_DENIED = -1;
-    public static final int ALREADY_EXISTS = -17;
-    public static final int BAD_VALUE = -22;
-    public static final int DEAD_OBJECT = -32;
-    public static final int INVALID_OPERATION = -38;
-    public static final int TIMED_OUT = -110;
+    public static final int PERMISSION_DENIED = -EPERM;
+    public static final int ALREADY_EXISTS = -EEXIST;
+    public static final int BAD_VALUE = -EINVAL;
+    public static final int DEAD_OBJECT = -ENOSYS;
+    public static final int INVALID_OPERATION = -EPIPE;
+    public static final int TIMED_OUT = -ETIMEDOUT;
 
     /**
      * TODO: add as error codes in Errors.h
@@ -52,12 +53,6 @@
      * - NOT_SUPPORTED
      * - TOO_MANY_USERS
      */
-    public static final int EACCES = -13;
-    public static final int EBUSY = -16;
-    public static final int ENODEV = -19;
-    public static final int EOPNOTSUPP = -95;
-    public static final int EUSERS = -87;
-
 
     static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
 
@@ -101,35 +96,34 @@
      * @param errorFlag error to throw as an exception.
      */
     public static void throwOnError(int errorFlag) {
-        switch (errorFlag) {
-            case NO_ERROR:
-                return;
-            case PERMISSION_DENIED:
-                throw new SecurityException("Lacking privileges to access camera service");
-            case ALREADY_EXISTS:
-                // This should be handled at the call site. Typically this isn't bad,
-                // just means we tried to do an operation that already completed.
-                return;
-            case BAD_VALUE:
-                throw new IllegalArgumentException("Bad argument passed to camera service");
-            case DEAD_OBJECT:
-                throw new CameraRuntimeException(CAMERA_DISCONNECTED);
-            case TIMED_OUT:
-                throw new CameraRuntimeException(CAMERA_ERROR,
-                        "Operation timed out in camera service");
-            case EACCES:
-                throw new CameraRuntimeException(CAMERA_DISABLED);
-            case EBUSY:
-                throw new CameraRuntimeException(CAMERA_IN_USE);
-            case EUSERS:
-                throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
-            case ENODEV:
-                throw new CameraRuntimeException(CAMERA_DISCONNECTED);
-            case EOPNOTSUPP:
-                throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
-            case INVALID_OPERATION:
-                throw new CameraRuntimeException(CAMERA_ERROR,
-                        "Illegal state encountered in camera service.");
+        if (errorFlag == NO_ERROR) {
+            return;
+        } else if (errorFlag == PERMISSION_DENIED) {
+            throw new SecurityException("Lacking privileges to access camera service");
+        } else if (errorFlag == ALREADY_EXISTS) {
+            // This should be handled at the call site. Typically this isn't bad,
+            // just means we tried to do an operation that already completed.
+            return;
+        } else if (errorFlag == BAD_VALUE) {
+            throw new IllegalArgumentException("Bad argument passed to camera service");
+        } else if (errorFlag == DEAD_OBJECT) {
+            throw new CameraRuntimeException(CAMERA_DISCONNECTED);
+        } else if (errorFlag == TIMED_OUT) {
+            throw new CameraRuntimeException(CAMERA_ERROR,
+                    "Operation timed out in camera service");
+        } else if (errorFlag == -EACCES) {
+            throw new CameraRuntimeException(CAMERA_DISABLED);
+        } else if (errorFlag == -EBUSY) {
+            throw new CameraRuntimeException(CAMERA_IN_USE);
+        } else if (errorFlag == -EUSERS) {
+            throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
+        } else if (errorFlag == -ENODEV) {
+            throw new CameraRuntimeException(CAMERA_DISCONNECTED);
+        } else if (errorFlag == -EOPNOTSUPP) {
+            throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
+        } else if (errorFlag == INVALID_OPERATION) {
+            throw new CameraRuntimeException(CAMERA_ERROR,
+                    "Illegal state encountered in camera service.");
         }
 
         /**
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 174291e..ff33bd9 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -24,6 +24,7 @@
 import android.os.IBinder;
 import android.view.InputDevice;
 import android.view.InputEvent;
+import android.view.PointerIcon;
 
 /** @hide */
 interface IInputManager {
@@ -71,4 +72,5 @@
     void cancelVibrate(int deviceId, IBinder token);
 
     void setPointerIconShape(int shapeId);
+    void setCustomPointerIcon(in PointerIcon icon);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 201afee..fab4718 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,6 +16,7 @@
 
 package android.hardware.input;
 
+import android.view.PointerIcon;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 
@@ -819,6 +820,15 @@
         }
     }
 
+    /** @hide */
+    public void setCustomPointerIcon(PointerIcon icon) {
+        try {
+            mIm.setCustomPointerIcon(icon);
+        } catch (RemoteException ex) {
+            // Do nothing.
+        }
+    }
+
     private void populateInputDevicesLocked() {
         if (mInputDevicesChangedListener == null) {
             final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index c85e97b..d490409 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -25,6 +25,8 @@
 import java.util.Arrays;
 import java.util.UUID;
 
+import static android.system.OsConstants.*;
+
 /**
  * The SoundTrigger class provides access via JNI to the native service managing
  * the sound trigger HAL.
@@ -35,11 +37,11 @@
 
     public static final int STATUS_OK = 0;
     public static final int STATUS_ERROR = Integer.MIN_VALUE;
-    public static final int STATUS_PERMISSION_DENIED = -1;
-    public static final int STATUS_NO_INIT = -19;
-    public static final int STATUS_BAD_VALUE = -22;
-    public static final int STATUS_DEAD_OBJECT = -32;
-    public static final int STATUS_INVALID_OPERATION = -38;
+    public static final int STATUS_PERMISSION_DENIED = -EPERM;
+    public static final int STATUS_NO_INIT = -ENODEV;
+    public static final int STATUS_BAD_VALUE = -EINVAL;
+    public static final int STATUS_DEAD_OBJECT = -EPIPE;
+    public static final int STATUS_INVALID_OPERATION = -ENOSYS;
 
     /*****************************************************************************
      * A ModuleProperties describes a given sound trigger hardware module
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 54bfca3..eca2c3b 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -144,6 +144,12 @@
     public static final int SHARED_RELRO_UID = 1037;
 
     /**
+     * Defines the UID/GID for the audioserver process.
+     * @hide
+     */
+    public static final int AUDIOSERVER_UID = 1041;
+
+    /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
      * to applications.
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 7529c52..9e8103a 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -79,6 +79,8 @@
     public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
     /** @hide */
     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
+    /** @hide */
+    public static final long TRACE_TAG_DATABASE = 1L << 20;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1346a39..1f16c4a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -776,6 +776,17 @@
     }
 
     /**
+     * Return whether the calling user is running in a "locked" state. A user is
+     * unlocked only after they've entered their credentials (such as a lock
+     * pattern or PIN), and credential-encrypted private app data storage is
+     * available.
+     */
+    @Deprecated
+    public boolean isUserRunningAndLocked() {
+        return isUserRunningAndLocked(Process.myUserHandle());
+    }
+
+    /**
      * Return whether the given user is running in a "locked" state. A user
      * is unlocked only after they've entered their credentials (such as a lock
      * pattern or PIN), and credential-encrypted private app data storage is
@@ -783,6 +794,7 @@
      *
      * @param user to retrieve the unlocked state for.
      */
+    @Deprecated
     public boolean isUserRunningAndLocked(UserHandle user) {
         try {
             return ActivityManagerNative.getDefault().isUserRunning(
@@ -793,6 +805,17 @@
     }
 
     /**
+     * Return whether the calling user is running in an "unlocked" state. A user
+     * is unlocked only after they've entered their credentials (such as a lock
+     * pattern or PIN), and credential-encrypted private app data storage is
+     * available.
+     */
+    @Deprecated
+    public boolean isUserRunningAndUnlocked() {
+        return isUserRunningAndUnlocked(Process.myUserHandle());
+    }
+
+    /**
      * Return whether the given user is running in an "unlocked" state. A user
      * is unlocked only after they've entered their credentials (such as a lock
      * pattern or PIN), and credential-encrypted private app data storage is
@@ -800,6 +823,7 @@
      *
      * @param user to retrieve the unlocked state for.
      */
+    @Deprecated
     public boolean isUserRunningAndUnlocked(UserHandle user) {
         try {
             return ActivityManagerNative.getDefault().isUserRunning(
@@ -810,6 +834,33 @@
     }
 
     /**
+     * Return whether the calling user is running in an "unlocked" state. A user
+     * is unlocked only after they've entered their credentials (such as a lock
+     * pattern or PIN), and credential-encrypted private app data storage is
+     * available.
+     */
+    public boolean isUserUnlocked() {
+        return isUserUnlocked(Process.myUserHandle());
+    }
+
+    /**
+     * Return whether the given user is running in an "unlocked" state. A user
+     * is unlocked only after they've entered their credentials (such as a lock
+     * pattern or PIN), and credential-encrypted private app data storage is
+     * available.
+     *
+     * @param user to retrieve the unlocked state for.
+     */
+    public boolean isUserUnlocked(UserHandle user) {
+        try {
+            return ActivityManagerNative.getDefault().isUserRunning(
+                    user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Returns the UserInfo object describing a specific user.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle the user handle of the user whose information is being requested.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 77a4485..084ff77 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -660,6 +660,16 @@
     }
 
     /**
+     * Builds URI for user home directory on external (local) storage.
+     * {@hide}
+     */
+    public static Uri buildHomeUri() {
+        // TODO: Avoid this type of interpackage copying. Added here to avoid
+        // direct coupling, but not ideal.
+        return DocumentsContract.buildRootUri("com.android.externalstorage.documents", "home");
+    }
+
+    /**
      * Build URI representing the recently modified documents of a specific root
      * in a document provider. When queried, a provider will return zero or more
      * rows with columns defined by {@link Document}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 521aa3c..a1e5510 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3323,6 +3323,7 @@
             PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
             PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
             PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+            PUBLIC_SETTINGS.add(VIBRATE_WHEN_RINGING);
         }
 
         /**
@@ -3344,7 +3345,6 @@
             PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
             PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
             PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
-            PRIVATE_SETTINGS.add(VIBRATE_WHEN_RINGING);
             PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING);
             PRIVATE_SETTINGS.add(HEARING_AID);
             PRIVATE_SETTINGS.add(TTY_MODE);
@@ -4912,6 +4912,15 @@
                 "accessibility_display_daltonizer";
 
         /**
+         * Float list that specifies the color matrix to apply to
+         * the display. Valid values are defined in AccessibilityManager.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_COLOR_MATRIX =
+                "accessibility_display_color_matrix";
+
+        /**
          * Setting that specifies whether automatic click when the mouse pointer stops moving is
          * enabled.
          *
@@ -5740,6 +5749,13 @@
                 "camera_double_tap_power_gesture_disabled";
 
         /**
+         * Name of the package used as WebView provider (if unset the provider is instead determined
+         * by the system).
+         * @hide
+         */
+        public static final String WEBVIEW_PROVIDER = "webview_provider";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/security/FrameworkNetworkSecurityPolicy.java b/core/java/android/security/FrameworkNetworkSecurityPolicy.java
new file mode 100644
index 0000000..e3dac5e
--- /dev/null
+++ b/core/java/android/security/FrameworkNetworkSecurityPolicy.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Android framework's implementation of {@link libcore.net.NetworkSecurityPolicy}.
+ *
+ * @hide
+ */
+public class FrameworkNetworkSecurityPolicy extends libcore.net.NetworkSecurityPolicy {
+    private final boolean mCleartextTrafficPermitted;
+
+    public FrameworkNetworkSecurityPolicy(boolean cleartextTrafficPermitted) {
+        mCleartextTrafficPermitted = cleartextTrafficPermitted;
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted() {
+        return mCleartextTrafficPermitted;
+    }
+}
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 7e87717..7991d37 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -60,7 +60,7 @@
      * <p>NOTE: {@link android.webkit.WebView} does not honor this flag.
      */
     public boolean isCleartextTrafficPermitted() {
-        return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted();
+        return libcore.net.NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted();
     }
 
     /**
@@ -72,6 +72,7 @@
      * @hide
      */
     public void setCleartextTrafficPermitted(boolean permitted) {
-        libcore.net.NetworkSecurityPolicy.setCleartextTrafficPermitted(permitted);
+        FrameworkNetworkSecurityPolicy policy = new FrameworkNetworkSecurityPolicy(permitted);
+        libcore.net.NetworkSecurityPolicy.setInstance(policy);
     }
 }
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index b627641..71d9d5d 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -68,7 +68,7 @@
      */
     public NetworkSecurityConfig getConfigForHostname(String hostname) {
         ensureInitialized();
-        if (hostname.isEmpty() || mConfigs == null) {
+        if (hostname == null || hostname.isEmpty() || mConfigs == null) {
             return mDefaultConfig;
         }
         if (hostname.charAt(0) ==  '.') {
diff --git a/core/java/android/security/net/config/CertificateSource.java b/core/java/android/security/net/config/CertificateSource.java
index 2b7829e..7e3601e 100644
--- a/core/java/android/security/net/config/CertificateSource.java
+++ b/core/java/android/security/net/config/CertificateSource.java
@@ -23,4 +23,5 @@
 public interface CertificateSource {
     Set<X509Certificate> getCertificates();
     X509Certificate findBySubjectAndPublicKey(X509Certificate cert);
+    X509Certificate findByIssuerAndSignature(X509Certificate cert);
 }
diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java
index 1d15e19..ff728ef 100644
--- a/core/java/android/security/net/config/CertificatesEntryRef.java
+++ b/core/java/android/security/net/config/CertificatesEntryRef.java
@@ -51,4 +51,13 @@
 
         return new TrustAnchor(foundCert, mOverridesPins);
     }
+
+    public TrustAnchor findByIssuerAndSignature(X509Certificate cert) {
+        X509Certificate foundCert = mSource.findByIssuerAndSignature(cert);
+        if (foundCert == null) {
+            return null;
+        }
+
+        return new TrustAnchor(foundCert, mOverridesPins);
+    }
 }
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index a261e06..bf29efa 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -95,6 +95,21 @@
         });
     }
 
+    @Override
+    public X509Certificate findByIssuerAndSignature(final X509Certificate cert) {
+        return findCert(cert.getIssuerX500Principal(), new CertSelector() {
+            @Override
+            public boolean match(X509Certificate ca) {
+                try {
+                    cert.verify(ca.getPublicKey());
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            }
+        });
+    }
+
     private static interface CertSelector {
         boolean match(X509Certificate cert);
     }
diff --git a/core/java/android/security/net/config/KeyStoreCertificateSource.java b/core/java/android/security/net/config/KeyStoreCertificateSource.java
index 7a01a64..b6105cd 100644
--- a/core/java/android/security/net/config/KeyStoreCertificateSource.java
+++ b/core/java/android/security/net/config/KeyStoreCertificateSource.java
@@ -80,4 +80,14 @@
         }
         return anchor.getTrustedCert();
     }
+
+    @Override
+    public X509Certificate findByIssuerAndSignature(X509Certificate cert) {
+        ensureInitialized();
+        java.security.cert.TrustAnchor anchor = mIndex.findByIssuerAndSignature(cert);
+        if (anchor == null) {
+            return null;
+        }
+        return anchor.getTrustedCert();
+    }
 }
diff --git a/core/java/android/security/net/config/ManifestConfigSource.java b/core/java/android/security/net/config/ManifestConfigSource.java
index bf1fb8a..0e137cd 100644
--- a/core/java/android/security/net/config/ManifestConfigSource.java
+++ b/core/java/android/security/net/config/ManifestConfigSource.java
@@ -79,7 +79,9 @@
                 if (DBG) {
                     Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
                 }
-                source = new DefaultConfigSource();
+                boolean usesCleartextTraffic =
+                        (info.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0;
+                source = new DefaultConfigSource(usesCleartextTraffic);
             }
             mConfigSource = source;
             return mConfigSource;
@@ -87,9 +89,18 @@
     }
 
     private static final class DefaultConfigSource implements ConfigSource {
+
+        private final NetworkSecurityConfig mDefaultConfig;
+
+        public DefaultConfigSource(boolean usesCleartextTraffic) {
+            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder()
+                    .setCleartextTrafficPermitted(usesCleartextTraffic)
+                    .build();
+       }
+
         @Override
         public NetworkSecurityConfig getDefaultConfig() {
-            return NetworkSecurityConfig.DEFAULT;
+            return mDefaultConfig;
         }
 
         @Override
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 2ab07b5..0a2edff 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -134,6 +134,17 @@
         return null;
     }
 
+    /** @hide */
+    public TrustAnchor findTrustAnchorByIssuerAndSignature(X509Certificate cert) {
+        for (CertificatesEntryRef ref : mCertificatesEntryRefs) {
+            TrustAnchor anchor = ref.findByIssuerAndSignature(cert);
+            if (anchor != null) {
+                return anchor;
+            }
+        }
+        return null;
+    }
+
     /**
      * Return a {@link Builder} for the default {@code NetworkSecurityConfig}.
      *
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index 6013c1e..982ed68 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -46,17 +46,13 @@
             throw new NullPointerException("config must not be null");
         }
         mNetworkSecurityConfig = config;
-        // TODO: Create our own better KeyStoreImpl
         try {
+            TrustedCertificateStoreAdapter certStore = new TrustedCertificateStoreAdapter(config);
+            // Provide an empty KeyStore since TrustManagerImpl doesn't support null KeyStores.
+            // TrustManagerImpl will use certStore to lookup certificates.
             KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
             store.load(null);
-            int certNum = 0;
-            for (TrustAnchor anchor : mNetworkSecurityConfig.getTrustAnchors()) {
-                store.setEntry(String.valueOf(certNum++),
-                        new KeyStore.TrustedCertificateEntry(anchor.certificate),
-                        null);
-            }
-            mDelegate = new TrustManagerImpl(store);
+            mDelegate = new TrustManagerImpl(store, null, certStore);
         } catch (GeneralSecurityException | IOException e) {
             throw new RuntimeException(e);
         }
diff --git a/core/java/android/security/net/config/ResourceCertificateSource.java b/core/java/android/security/net/config/ResourceCertificateSource.java
index b007f8f..e489c2c 100644
--- a/core/java/android/security/net/config/ResourceCertificateSource.java
+++ b/core/java/android/security/net/config/ResourceCertificateSource.java
@@ -90,4 +90,14 @@
         }
         return anchor.getTrustedCert();
     }
+
+    @Override
+    public X509Certificate findByIssuerAndSignature(X509Certificate cert) {
+        ensureInitialized();
+        java.security.cert.TrustAnchor anchor = mIndex.findByIssuerAndSignature(cert);
+        if (anchor == null) {
+            return null;
+        }
+        return anchor.getTrustedCert();
+    }
 }
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index e307ad0..b4e58e6 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -71,6 +71,10 @@
      */
     public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType,
             String hostname) throws CertificateException {
+        if (hostname == null && mConfig.hasPerDomainConfigs()) {
+            throw new CertificateException(
+                    "Domain specific configurations require that the hostname be provided");
+        }
         NetworkSecurityConfig config = mConfig.getConfigForHostname(hostname);
         return config.getTrustManager().checkServerTrusted(certs, authType, hostname);
     }
diff --git a/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java b/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
new file mode 100644
index 0000000..4a90f82
--- /dev/null
+++ b/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.net.config;
+
+import java.io.File;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Set;
+
+import com.android.org.conscrypt.TrustedCertificateStore;
+
+/** @hide */
+public class TrustedCertificateStoreAdapter extends TrustedCertificateStore {
+    private final NetworkSecurityConfig mConfig;
+
+    public TrustedCertificateStoreAdapter(NetworkSecurityConfig config) {
+        mConfig = config;
+    }
+
+    @Override
+    public X509Certificate findIssuer(X509Certificate cert) {
+        TrustAnchor anchor = mConfig.findTrustAnchorByIssuerAndSignature(cert);
+        if (anchor == null) {
+            return null;
+        }
+        return anchor.certificate;
+    }
+
+    @Override
+    public X509Certificate getTrustAnchor(X509Certificate cert) {
+        TrustAnchor anchor = mConfig.findTrustAnchorBySubjectAndPublicKey(cert);
+        if (anchor == null) {
+            return null;
+        }
+        return anchor.certificate;
+    }
+
+    @Override
+    public boolean isUserAddedCertificate(X509Certificate cert) {
+        // isUserAddedCertificate is used only for pinning overrides, so use overridesPins here.
+        TrustAnchor anchor = mConfig.findTrustAnchorBySubjectAndPublicKey(cert);
+        if (anchor == null) {
+            return false;
+        }
+        return anchor.overridesPins;
+    }
+
+    @Override
+    public File getCertificateFile(File dir, X509Certificate x) {
+        // getCertificateFile is only used for tests, do not support it here.
+        throw new UnsupportedOperationException();
+    }
+
+    // The methods below are exposed in TrustedCertificateStore but not used by conscrypt, do not
+    // support them.
+
+    @Override
+    public Certificate getCertificate(String alias) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Certificate getCertificate(String alias, boolean includeDeletedSystem) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Date getCreationDate(String alias) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> aliases() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> userAliases() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<String> allSystemAliases() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean containsAlias(String alias) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCertificateAlias(Certificate c) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCertificateAlias(Certificate c, boolean includeDeletedSystem) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a7545f2..232d4fe 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -713,10 +713,10 @@
                 createLegacyIconExtras(sbn.getNotification());
                 maybePopulateRemoteViews(sbn.getNotification());
             } catch (IllegalArgumentException e) {
-                // drop corrupt notification
-                sbn = null;
+                // warn and drop corrupt notification
                 Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
                         sbn.getPackageName());
+                sbn = null;
             }
 
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
@@ -833,29 +833,29 @@
         /**
          * A notification with no importance: shows nowhere, is blocked.
          */
-        public static final int IMPORTANCE_NONE = -2;
+        public static final int IMPORTANCE_NONE = 0;
 
         /**
          * Low notification importance: only shows in the shade, below the fold.
          */
-        public static final int IMPORTANCE_LOW = -1;
+        public static final int IMPORTANCE_LOW = 1;
 
         /**
          * Default notification importance: shows everywhere, but is not intrusive.
          */
-        public static final int IMPORTANCE_DEFAULT = 0;
+        public static final int IMPORTANCE_DEFAULT = 2;
 
         /**
          * Higher notification importance: shows everywhere, makes noise,
          * but does not visually intrude.
          */
-        public static final int IMPORTANCE_HIGH = 1;
+        public static final int IMPORTANCE_HIGH = 3;
 
         /**
          * Highest notification importance: shows everywhere, makes noise,
          * and also visually intrudes.
          */
-        public static final int IMPORTANCE_MAX = 2;
+        public static final int IMPORTANCE_MAX = 4;
 
         private String mKey;
         private int mRank = -1;
@@ -863,6 +863,8 @@
         private boolean mMatchesInterruptionFilter;
         private int mVisibilityOverride;
         private int mSuppressedVisualEffects;
+        private int mImportance;
+        private CharSequence mImportanceExplanation;
 
         public Ranking() {}
 
@@ -928,7 +930,7 @@
          * @return the rank of the notification
          */
         public int getImportance() {
-            return IMPORTANCE_DEFAULT;  // TODO implement;
+            return mImportance;
         }
 
         /**
@@ -939,18 +941,21 @@
          * @return the explanation for the importance, or null if it is the natural importance
          */
         public CharSequence getImportanceExplanation() {
-            return null;  // TODO implement
+            return mImportanceExplanation;
         }
 
         private void populate(String key, int rank, boolean isAmbient,
                 boolean matchesInterruptionFilter, int visibilityOverride,
-                int suppressedVisualEffects) {
+                int suppressedVisualEffects, int importance,
+                CharSequence explanation) {
             mKey = key;
             mRank = rank;
             mIsAmbient = isAmbient;
             mMatchesInterruptionFilter = matchesInterruptionFilter;
             mVisibilityOverride = visibilityOverride;
             mSuppressedVisualEffects = suppressedVisualEffects;
+            mImportance = importance;
+            mImportanceExplanation = explanation;
         }
 
         /**
@@ -990,6 +995,8 @@
         private ArraySet<Object> mIntercepted;
         private ArrayMap<String, Integer> mVisibilityOverrides;
         private ArrayMap<String, Integer> mSuppressedVisualEffects;
+        private ArrayMap<String, Integer> mImportance;
+        private ArrayMap<String, String> mImportanceExplanation;
 
         private RankingMap(NotificationRankingUpdate rankingUpdate) {
             mRankingUpdate = rankingUpdate;
@@ -1015,7 +1022,8 @@
         public boolean getRanking(String key, Ranking outRanking) {
             int rank = getRank(key);
             outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key),
-                    getVisibilityOverride(key), getSuppressedVisualEffects(key));
+                    getVisibilityOverride(key), getSuppressedVisualEffects(key),
+                    getImportance(key), getImportanceExplanation(key));
             return rank >= 0;
         }
 
@@ -1073,6 +1081,28 @@
             return suppressed.intValue();
         }
 
+        private int getImportance(String key) {
+            synchronized (this) {
+                if (mImportance == null) {
+                    buildImportanceLocked();
+                }
+            }
+            Integer importance = mImportance.get(key);
+            if (importance == null) {
+                return Ranking.IMPORTANCE_DEFAULT;
+            }
+            return importance.intValue();
+        }
+
+        private String getImportanceExplanation(String key) {
+            synchronized (this) {
+                if (mImportanceExplanation == null) {
+                    buildImportanceExplanationLocked();
+                }
+            }
+            return mImportanceExplanation.get(key);
+        }
+
         // Locked by 'this'
         private void buildRanksLocked() {
             String[] orderedKeys = mRankingUpdate.getOrderedKeys();
@@ -1107,6 +1137,25 @@
                 mSuppressedVisualEffects.put(key, suppressedBundle.getInt(key));
             }
         }
+        // Locked by 'this'
+        private void buildImportanceLocked() {
+            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
+            int[] importance = mRankingUpdate.getImportance();
+            mImportance = new ArrayMap<>(orderedKeys.length);
+            for (int i = 0; i < orderedKeys.length; i++) {
+                String key = orderedKeys[i];
+                mImportance.put(key, importance[i]);
+            }
+        }
+
+        // Locked by 'this'
+        private void buildImportanceExplanationLocked() {
+            Bundle explanationBundle = mRankingUpdate.getImportanceExplanation();
+            mImportanceExplanation = new ArrayMap<>(explanationBundle.size());
+            for (String key: explanationBundle.keySet()) {
+                mImportanceExplanation.put(key, explanationBundle.getString(key));
+            }
+        }
 
         // ----------- Parcelable
 
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 1282fb1..0d42ffb 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -29,14 +29,19 @@
     private final int mFirstAmbientIndex;
     private final Bundle mVisibilityOverrides;
     private final Bundle mSuppressedVisualEffects;
+    private final int[] mImportance;
+    private final Bundle mImportanceExplanation;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
-            Bundle visibilityOverrides, int firstAmbientIndex, Bundle suppressedVisualEffects) {
+            Bundle visibilityOverrides, int firstAmbientIndex, Bundle suppressedVisualEffects,
+            int[] importance, Bundle explanation) {
         mKeys = keys;
         mFirstAmbientIndex = firstAmbientIndex;
         mInterceptedKeys = interceptedKeys;
         mVisibilityOverrides = visibilityOverrides;
         mSuppressedVisualEffects = suppressedVisualEffects;
+        mImportance = importance;
+        mImportanceExplanation = explanation;
     }
 
     public NotificationRankingUpdate(Parcel in) {
@@ -45,6 +50,9 @@
         mInterceptedKeys = in.readStringArray();
         mVisibilityOverrides = in.readBundle();
         mSuppressedVisualEffects = in.readBundle();
+        mImportance = new int[mKeys.length];
+        in.readIntArray(mImportance);
+        mImportanceExplanation = in.readBundle();
     }
 
     @Override
@@ -59,6 +67,8 @@
         out.writeStringArray(mInterceptedKeys);
         out.writeBundle(mVisibilityOverrides);
         out.writeBundle(mSuppressedVisualEffects);
+        out.writeIntArray(mImportance);
+        out.writeBundle(mImportanceExplanation);
     }
 
     public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -91,4 +101,12 @@
     public Bundle getSuppressedVisualEffects() {
         return mSuppressedVisualEffects;
     }
+
+    public int[] getImportance() {
+        return mImportance;
+    }
+
+    public Bundle getImportanceExplanation() {
+        return mImportanceExplanation;
+    }
 }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 2cab914..198e43d 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -42,7 +42,6 @@
     private final UserHandle user;
     private final long postTime;
 
-    private final int score;
     private Context mContext; // used for inflation & icon expansion
 
     /** @hide */
@@ -64,7 +63,6 @@
         this.tag = tag;
         this.uid = uid;
         this.initialPid = initialPid;
-        this.score = score;
         this.notification = notification;
         this.user = user;
         this.postTime = postTime;
@@ -83,7 +81,6 @@
         }
         this.uid = in.readInt();
         this.initialPid = in.readInt();
-        this.score = in.readInt();
         this.notification = new Notification(in);
         this.user = UserHandle.readFromParcel(in);
         this.postTime = in.readLong();
@@ -120,7 +117,6 @@
         }
         out.writeInt(this.uid);
         out.writeInt(this.initialPid);
-        out.writeInt(this.score);
         this.notification.writeToParcel(out, flags);
         user.writeToParcel(out, flags);
 
@@ -153,14 +149,14 @@
         this.notification.cloneInto(no, false); // light copy
         return new StatusBarNotification(this.pkg, this.opPkg,
                 this.id, this.tag, this.uid, this.initialPid,
-                this.score, no, this.user, this.postTime);
+                0, no, this.user, this.postTime);
     }
 
     @Override
     public StatusBarNotification clone() {
         return new StatusBarNotification(this.pkg, this.opPkg,
                 this.id, this.tag, this.uid, this.initialPid,
-                this.score, this.notification.clone(), this.user, this.postTime);
+                0, this.notification.clone(), this.user, this.postTime);
     }
 
     @Override
@@ -168,7 +164,7 @@
         return String.format(
                 "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
                 this.pkg, this.user, this.id, this.tag,
-                this.score, this.key, this.notification);
+                0, this.key, this.notification);
     }
 
     /** Convenience method to check the notification's flags for
@@ -247,11 +243,6 @@
         return postTime;
     }
 
-    /** @hide */
-    public int getScore() {
-        return score;
-    }
-
     /**
      * A unique instance key for this notification record.
      */
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 5d9d929..568b267 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -72,10 +72,20 @@
                 return result;
             }
 
-            // TODO: Convert this a proper locale-fallback system
+            // If there's a variant, fall back to language+variant only, if available
+            final String variant = locale.getVariant();
+            if (!variant.isEmpty()) {
+                final Locale languageAndVariantOnlyLocale =
+                        new Locale(locale.getLanguage(), "", variant);
+                result = sMap.get(languageAndVariantOnlyLocale);
+                if (result != null) {
+                    sMap.put(locale, result);
+                    return result;
+                }
+            }
 
             // Fall back to language-only, if available
-            Locale languageOnlyLocale = new Locale(locale.getLanguage());
+            final Locale languageOnlyLocale = new Locale(locale.getLanguage());
             result = sMap.get(languageOnlyLocale);
             if (result != null) {
                 sMap.put(locale, result);
@@ -83,9 +93,9 @@
             }
 
             // Fall back to script-only, if available
-            String script = locale.getScript();
+            final String script = locale.getScript();
             if (!script.equals("")) {
-                Locale scriptOnlyLocale = new Locale.Builder()
+                final Locale scriptOnlyLocale = new Locale.Builder()
                         .setLanguage("und")
                         .setScript(script)
                         .build();
@@ -142,6 +152,11 @@
         {"en-UM", "en-US"}, // English (United States Minor Outlying Islands)
         {"en-VI", "en-US"}, // English (Virgin Islands)
 
+        // For German, we're assuming the 1996 (and later) orthography by default.
+        {"de", "de-1996"},
+        // Liechtenstein uses the Swiss hyphenation rules for the 1901 orthography.
+        {"de-LI-1901", "de-CH-1901"},
+
         // Norwegian is very probably Norwegian Bokmål.
         {"no", "nb"},
 
@@ -166,7 +181,18 @@
         sMap.put(null, null);
 
         // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
-        String[] availableLanguages = {"en-US", "es", "eu", "hu", "hy", "nb", "nn", "und-Ethi"};
+        String[] availableLanguages = {
+            "de-1901", "de-1996", "de-CH-1901",
+            "en-US",
+            "es",
+            "eu",
+            "hu",
+            "hy",
+            "nb",
+            "nn",
+            "pt",
+            "und-Ethi"
+        };
         for (int i = 0; i < availableLanguages.length; i++) {
             String languageTag = availableLanguages[i];
             Hyphenator h = loadHyphenator(languageTag);
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 2459cfa..57fe131 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -20,7 +20,6 @@
 import android.text.Layout;
 import android.text.Selection;
 import android.text.Spannable;
-import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -222,34 +221,26 @@
         return lineEnd(widget, buffer);
     }
 
-    private static boolean isTouchSelecting(boolean isMouse, Spannable buffer) {
-        return isMouse ? Touch.isActivelySelecting(buffer) : isSelecting(buffer);
-    }
-
     @Override
     public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
         int initialScrollX = -1;
         int initialScrollY = -1;
         final int action = event.getAction();
-        final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
 
         if (action == MotionEvent.ACTION_UP) {
             initialScrollX = Touch.getInitialScrollX(widget, buffer);
             initialScrollY = Touch.getInitialScrollY(widget, buffer);
         }
 
-        boolean wasTouchSelecting = isTouchSelecting(isMouse, buffer);
+        boolean wasTouchSelecting = isSelecting(buffer);
         boolean handled = Touch.onTouchEvent(widget, buffer, event);
 
-        if (widget.didTouchFocusSelect() && !isMouse) {
+        if (widget.didTouchFocusSelect()) {
             return handled;
         }
         if (action == MotionEvent.ACTION_DOWN) {
-            // Capture the mouse pointer down location to ensure selection starts
-            // right under the mouse (and is not influenced by cursor location).
-            // The code below needs to run for mouse events.
             // For touch events, the code should run only when selection is active.
-            if (isMouse || isTouchSelecting(isMouse, buffer)) {
+            if (isSelecting(buffer)) {
                 if (!widget.isFocused()) {
                     if (!widget.requestFocus()) {
                         return handled;
@@ -265,15 +256,8 @@
             }
         } else if (widget.isFocused()) {
             if (action == MotionEvent.ACTION_MOVE) {
-                // Cursor can be active at any location in the text while mouse pointer can start
-                // selection from a totally different location. Use LAST_TAP_DOWN span to ensure
-                // text selection will start from mouse pointer location.
-                final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN);
-                if (isMouse && Touch.isSelectionStarted(buffer)) {
-                    Selection.setSelection(buffer, startOffset);
-                }
-
-                if (isTouchSelecting(isMouse, buffer) && handled) {
+                if (isSelecting(buffer) && handled) {
+                    final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN);
                     // Before selecting, make sure we've moved out of the "slop".
                     // handled will be true, if we're in select mode AND we're
                     // OUT of the slop
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index fee7377..d9068dc 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -119,18 +119,12 @@
             ds = buffer.getSpans(0, buffer.length(), DragState.class);
 
             if (ds.length > 0) {
-                ds[0].mIsSelectionStarted = false;
-
                 if (ds[0].mFarEnough == false) {
                     int slop = ViewConfiguration.get(widget.getContext()).getScaledTouchSlop();
 
                     if (Math.abs(event.getX() - ds[0].mX) >= slop ||
                         Math.abs(event.getY() - ds[0].mY) >= slop) {
                         ds[0].mFarEnough = true;
-                        if (event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
-                            ds[0].mIsActivelySelecting = true;
-                            ds[0].mIsSelectionStarted = true;
-                        }
                     }
                 }
 
@@ -142,13 +136,9 @@
                             || MetaKeyKeyListener.getMetaState(buffer,
                                     MetaKeyKeyListener.META_SELECTING) != 0;
 
-                    if (!event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
-                        ds[0].mIsActivelySelecting = false;
-                    }
-
                     float dx;
                     float dy;
-                    if (cap && event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
+                    if (cap) {
                         // if we're selecting, we want the scroll to go in
                         // the direction of the drag
                         dx = event.getX() - ds[0].mX;
@@ -160,7 +150,6 @@
                     ds[0].mX = event.getX();
                     ds[0].mY = event.getY();
 
-                    int nx = widget.getScrollX() + (int) dx;
                     int ny = widget.getScrollY() + (int) dy;
 
                     int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
@@ -172,10 +161,6 @@
                     int oldX = widget.getScrollX();
                     int oldY = widget.getScrollY();
 
-                    if (!event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
-                        scrollTo(widget, layout, nx, ny);
-                    }
-
                     // If we actually scrolled, then cancel the up action.
                     if (oldX != widget.getScrollX() || oldY != widget.getScrollY()) {
                         widget.cancelLongPress();
@@ -207,37 +192,6 @@
         return ds.length > 0 ? ds[0].mScrollY : -1;
     }
 
-    /**
-     * Checks if selection is still active.
-     * This is useful for extending Selection span on buffer.
-     * @param buffer The text buffer.
-     * @return true if buffer has been marked for selection.
-     *
-     * @hide
-     */
-    static boolean isActivelySelecting(Spannable buffer) {
-        DragState[] ds;
-        ds = buffer.getSpans(0, buffer.length(), DragState.class);
-
-        return ds.length > 0 && ds[0].mIsActivelySelecting;
-    }
-
-    /**
-     * Checks if selection has begun (are we out of slop?).
-     * Note: DragState.mIsSelectionStarted goes back to false with the very next event.
-     * This is useful for starting Selection span on buffer.
-     * @param buffer The text buffer.
-     * @return true if selection has started on the buffer.
-     *
-     * @hide
-     */
-    static boolean isSelectionStarted(Spannable buffer) {
-        DragState[] ds;
-        ds = buffer.getSpans(0, buffer.length(), DragState.class);
-
-        return ds.length > 0 && ds[0].mIsSelectionStarted;
-    }
-
     private static class DragState implements NoCopySpan {
         public float mX;
         public float mY;
@@ -245,8 +199,6 @@
         public int mScrollY;
         public boolean mFarEnough;
         public boolean mUsed;
-        public boolean mIsActivelySelecting;
-        public boolean mIsSelectionStarted;
 
         public DragState(float x, float y, int scrollX, int scrollY) {
             mX = x;
diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java
index 3688cfa..664d1ea 100644
--- a/core/java/android/text/method/WordIterator.java
+++ b/core/java/android/text/method/WordIterator.java
@@ -20,7 +20,7 @@
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 
-import java.text.BreakIterator;
+import android.icu.text.BreakIterator;
 import java.util.Locale;
 
 /**
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 46b9a46..88cd7ca 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -784,6 +784,15 @@
     }
 
     /**
+     * Specifies the current custom pointer.
+     * @param icon the icon data.
+     * @hide
+     */
+    public void setCustomPointerIcon(PointerIcon icon) {
+        InputManager.getInstance().setCustomPointerIcon(icon);
+    }
+
+    /**
      * Provides information about the range of values for a particular {@link MotionEvent} axis.
      *
      * @see InputDevice#getMotionRange(int)
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 55cf56f..f037958 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1779,6 +1779,7 @@
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_CENTER:
             case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_SPACE:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 527d7e5..0195dec 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -973,7 +973,6 @@
      * </p>
      *
      * @see #getAxisValue(int, int)
-     * {@hide}
      */
     public static final int AXIS_SCROLL = 26;
 
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index d2a7d4a..aa879cd 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -16,8 +16,10 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.SparseArray;
 import com.android.internal.util.XmlUtils;
 
 import android.annotation.XmlRes;
@@ -39,13 +41,11 @@
  * Pointer icons can be provided either by the system using system styles,
  * or by applications using bitmaps or application resources.
  * </p>
- *
- * @hide
  */
 public final class PointerIcon implements Parcelable {
     private static final String TAG = "PointerIcon";
 
-    /** Style constant: Custom icon with a user-supplied bitmap. */
+    /** {@hide} Style constant: Custom icon with a user-supplied bitmap. */
     public static final int STYLE_CUSTOM = -1;
 
     /** Style constant: Null icon.  It has no bitmap. */
@@ -54,6 +54,7 @@
     /** Style constant: no icons are specified. If all views uses this, then falls back
      * to the default style, but this is helpful to distinguish a view explicitly want
      * to have the default icon.
+     * @hide
      */
     public static final int STYLE_NOT_SPECIFIED = 1;
 
@@ -135,10 +136,11 @@
     // conflicts with any system styles that may be defined in the future.
     private static final int STYLE_OEM_FIRST = 10000;
 
-    /** {@hide} The default pointer icon. */
+    /** The default pointer icon. */
     public static final int STYLE_DEFAULT = STYLE_ARROW;
 
     private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL);
+    private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
 
     private final int mStyle;
     private int mSystemIconResourceId;
@@ -160,6 +162,7 @@
      * @return The null pointer icon.
      *
      * @see #STYLE_NULL
+     * @hide
      */
     public static PointerIcon getNullIcon() {
         return gNullIcon;
@@ -172,8 +175,9 @@
      * @return The default pointer icon.
      *
      * @throws IllegalArgumentException if context is null.
+     * @hide
      */
-    public static PointerIcon getDefaultIcon(Context context) {
+    public static PointerIcon getDefaultIcon(@NonNull Context context) {
         return getSystemIcon(context, STYLE_DEFAULT);
     }
 
@@ -187,7 +191,7 @@
      *
      * @throws IllegalArgumentException if context is null.
      */
-    public static PointerIcon getSystemIcon(Context context, int style) {
+    public static PointerIcon getSystemIcon(@NonNull Context context, int style) {
         if (context == null) {
             throw new IllegalArgumentException("context must not be null");
         }
@@ -196,6 +200,11 @@
             return gNullIcon;
         }
 
+        PointerIcon icon = gSystemIcons.get(style);
+        if (icon != null) {
+            return icon;
+        }
+
         int styleIndex = getSystemIconStyleIndex(style);
         if (styleIndex == 0) {
             styleIndex = getSystemIconStyleIndex(STYLE_DEFAULT);
@@ -217,12 +226,13 @@
             return style == STYLE_DEFAULT ? gNullIcon : getSystemIcon(context, STYLE_DEFAULT);
         }
 
-        PointerIcon icon = new PointerIcon(style);
+        icon = new PointerIcon(style);
         if ((resourceId & 0xff000000) == 0x01000000) {
             icon.mSystemIconResourceId = resourceId;
         } else {
             icon.loadResource(context, context.getResources(), resourceId);
         }
+        gSystemIcons.append(style, icon);
         return icon;
     }
 
@@ -239,7 +249,8 @@
      * @throws IllegalArgumentException if bitmap is null, or if the x/y hotspot
      *         parameters are invalid.
      */
-    public static PointerIcon createCustomIcon(Bitmap bitmap, float hotSpotX, float hotSpotY) {
+    public static PointerIcon createCustomIcon(
+            @NonNull Bitmap bitmap, float hotSpotX, float hotSpotY) {
         if (bitmap == null) {
             throw new IllegalArgumentException("bitmap must not be null");
         }
@@ -273,7 +284,7 @@
      * @throws Resources.NotFoundException if the resource was not found or the drawable
      * linked in the resource was not found.
      */
-    public static PointerIcon loadCustomIcon(Resources resources, @XmlRes int resourceId) {
+    public static PointerIcon loadCustomIcon(@NonNull Resources resources, @XmlRes int resourceId) {
         if (resources == null) {
             throw new IllegalArgumentException("resources must not be null");
         }
@@ -291,10 +302,9 @@
      * @return The loaded pointer icon.
      *
      * @throws IllegalArgumentException if context is null.
-     * @see #isLoaded()
      * @hide
      */
-    public PointerIcon load(Context context) {
+    public PointerIcon load(@NonNull Context context) {
         if (context == null) {
             throw new IllegalArgumentException("context must not be null");
         }
@@ -309,83 +319,11 @@
         return result;
     }
 
-    /**
-     * Returns true if the pointer icon style is {@link #STYLE_NULL}.
-     *
-     * @return True if the pointer icon style is {@link #STYLE_NULL}.
-     */
-    public boolean isNullIcon() {
-        return mStyle == STYLE_NULL;
-    }
-
-    /**
-     * Returns true if the pointer icon has been loaded and its bitmap and hotspot
-     * information are available.
-     *
-     * @return True if the pointer icon is loaded.
-     * @see #load(Context)
-     */
-    public boolean isLoaded() {
-        return mBitmap != null || mStyle == STYLE_NULL;
-    }
-
-    /**
-     * Gets the style of the pointer icon.
-     *
-     * @return The pointer icon style.
-     */
+    /** @hide */
     public int getStyle() {
         return mStyle;
     }
 
-    /**
-     * Gets the bitmap of the pointer icon.
-     *
-     * @return The pointer icon bitmap, or null if the style is {@link #STYLE_NULL}.
-     *
-     * @throws IllegalStateException if the bitmap is not loaded.
-     * @see #isLoaded()
-     * @see #load(Context)
-     */
-    public Bitmap getBitmap() {
-        throwIfIconIsNotLoaded();
-        return mBitmap;
-    }
-
-    /**
-     * Gets the X offset of the pointer icon hotspot.
-     *
-     * @return The hotspot X offset.
-     *
-     * @throws IllegalStateException if the bitmap is not loaded.
-     * @see #isLoaded()
-     * @see #load(Context)
-     */
-    public float getHotSpotX() {
-        throwIfIconIsNotLoaded();
-        return mHotSpotX;
-    }
-
-    /**
-     * Gets the Y offset of the pointer icon hotspot.
-     *
-     * @return The hotspot Y offset.
-     *
-     * @throws IllegalStateException if the bitmap is not loaded.
-     * @see #isLoaded()
-     * @see #load(Context)
-     */
-    public float getHotSpotY() {
-        throwIfIconIsNotLoaded();
-        return mHotSpotY;
-    }
-
-    private void throwIfIconIsNotLoaded() {
-        if (!isLoaded()) {
-            throw new IllegalStateException("The icon is not loaded.");
-        }
-    }
-
     public static final Parcelable.Creator<PointerIcon> CREATOR
             = new Parcelable.Creator<PointerIcon>() {
         public PointerIcon createFromParcel(Parcel in) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 183ccf3..afa6c78 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2628,7 +2628,7 @@
     static final int PFLAG3_POINTER_ICON_LSHIFT = 15;
 
     /**
-     * Value indicating {@link PointerIcon.STYLE_NOT_SPECIFIED}.
+     * Value indicating no specific pointer icons.
      */
     private static final int PFLAG3_POINTER_ICON_NOT_SPECIFIED = 0 << PFLAG3_POINTER_ICON_LSHIFT;
 
@@ -2638,14 +2638,9 @@
     private static final int PFLAG3_POINTER_ICON_NULL = 1 << PFLAG3_POINTER_ICON_LSHIFT;
 
     /**
-     * Value incicating {@link PointerIcon.STYLE_CUSTOM}.
-     */
-    private static final int PFLAG3_POINTER_ICON_CUSTOM = 2 << PFLAG3_POINTER_ICON_LSHIFT;
-
-    /**
      * The base value for other pointer icon shapes.
      */
-    private static final int PFLAG3_POINTER_ICON_VALUE_START = 3 << PFLAG3_POINTER_ICON_LSHIFT;
+    private static final int PFLAG3_POINTER_ICON_VALUE_START = 2 << PFLAG3_POINTER_ICON_LSHIFT;
 
     /**
      * Always allow a user to over-scroll this view, provided it is a
@@ -3927,6 +3922,11 @@
     private HandlerActionQueue mRunQueue;
 
     /**
+     * The pointer icon when the mouse hovers on this view. The default is null.
+     */
+    private PointerIcon mPointerIcon;
+
+    /**
      * @hide
      */
     String mStartActivityRequestWho;
@@ -4487,6 +4487,12 @@
                         initializeScrollIndicators = true;
                     }
                     break;
+                case R.styleable.View_pointerShape:
+                    final int pointerShape = a.getInt(attr, PointerIcon.STYLE_NOT_SPECIFIED);
+                    if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) {
+                        setPointerIcon(PointerIcon.getSystemIcon(context, pointerShape));
+                    }
+                    break;
             }
         }
 
@@ -10156,8 +10162,8 @@
     /**
      * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent)
      * KeyEvent.Callback.onKeyUp()}: perform clicking of the view
-     * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
-     * {@link KeyEvent#KEYCODE_ENTER} is released.
+     * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER}
+     * or {@link KeyEvent#KEYCODE_SPACE} is released.
      * <p>Key presses in software keyboards will generally NOT trigger this listener,
      * although some may elect to do so in some situations. Do not rely on this to
      * catch software key presses.
@@ -21185,42 +21191,25 @@
         }
     }
 
-    /** @hide */
-    public int getPointerShape(MotionEvent event, float x, float y) {
-        final int value = (mPrivateFlags3 & PFLAG3_POINTER_ICON_MASK);
-        switch (value) {
-            case PFLAG3_POINTER_ICON_NOT_SPECIFIED:
-                return PointerIcon.STYLE_NOT_SPECIFIED;
-            case PFLAG3_POINTER_ICON_NULL:
-                return PointerIcon.STYLE_NULL;
-            case PFLAG3_POINTER_ICON_CUSTOM:
-                return PointerIcon.STYLE_CUSTOM;
-            default:
-                return ((value - PFLAG3_POINTER_ICON_VALUE_START) >> PFLAG3_POINTER_ICON_LSHIFT)
-                        + PointerIcon.STYLE_ARROW;
-        }
+    /**
+     * Returns the pointer icon for the motion event, or null if it doesn't specify the icon.
+     * The default implementation does not care the location or event types, but some subclasses
+     * may use it (such as WebViews).
+     * @param event The MotionEvent from a mouse
+     * @param x The x position of the event, local to the view
+     * @param y The y position of the event, local to the view
+     * @see PointerIcon
+     */
+    public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
+        return mPointerIcon;
     }
 
-    /** @hide */
-    public void setPointerShape(int pointerShape) {
-        int newValue;
-        if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) {
-            newValue = PFLAG3_POINTER_ICON_NOT_SPECIFIED;
-        } else if (pointerShape == PointerIcon.STYLE_NULL) {
-            newValue = PFLAG3_POINTER_ICON_NULL;
-        } else if (pointerShape == PointerIcon.STYLE_CUSTOM) {
-            newValue = PFLAG3_POINTER_ICON_CUSTOM;
-        } else if (pointerShape >= PointerIcon.STYLE_ARROW
-                && pointerShape <= PointerIcon.STYLE_GRABBING) {
-            newValue = ((pointerShape - PointerIcon.STYLE_ARROW) << PFLAG3_POINTER_ICON_LSHIFT)
-                    + PFLAG3_POINTER_ICON_VALUE_START;
-        } else {
-            Log.w(VIEW_LOG_TAG, "Invalid pointer shape " + pointerShape + " is specified.");
-            return;
-        }
-        if (newValue != (mPrivateFlags3 & PFLAG3_POINTER_ICON_MASK)) {
-            mPrivateFlags3 = (mPrivateFlags3 & ~PFLAG3_POINTER_ICON_MASK) | newValue;
-        }
+    /**
+     * Set the pointer icon for the current view.
+     * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers.
+     */
+    public void setPointerIcon(PointerIcon pointerIcon) {
+        mPointerIcon = pointerIcon;
     }
 
     //
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0f7d296..cd93dab 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1715,9 +1715,8 @@
         return false;
     }
 
-    /** @hide */
     @Override
-    public int getPointerShape(MotionEvent event, float x, float y) {
+    public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
         // Check what the child under the pointer says about the pointer.
         final int childrenCount = mChildrenCount;
         if (childrenCount != 0) {
@@ -1731,9 +1730,9 @@
                         ? children[childIndex] : preorderedList.get(childIndex);
                 PointF point = getLocalPoint();
                 if (isTransformedTouchPointInView(x, y, child, point)) {
-                    final int pointerShape = child.getPointerShape(event, point.x, point.y);
-                    if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) {
-                        return pointerShape;
+                    final PointerIcon pointerIcon = child.getPointerIcon(event, point.x, point.y);
+                    if (pointerIcon != null) {
+                        return pointerIcon;
                     }
                     break;
                 }
@@ -1742,7 +1741,7 @@
 
         // The pointer is not a child or the child has no preferences, returning the default
         // implementation.
-        return super.getPointerShape(event, x, y);
+        return super.getPointerIcon(event, x, y);
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 12cf66e..faf2640 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -332,6 +332,7 @@
     private int mFpsNumFrames;
 
     private int mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
+    private PointerIcon mCustomPointerIcon = null;
 
     /**
      * see {@link #playSoundEffect(int)}
@@ -4210,16 +4211,23 @@
                 final float y = event.getY();
                 if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT
                         && x >= 0 && x < mView.getWidth() && y >= 0 && y < mView.getHeight()) {
-                    int pointerShape = mView.getPointerShape(event, x, y);
-                    if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) {
-                        pointerShape = PointerIcon.STYLE_DEFAULT;
-                    }
+                    PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
+                    int pointerShape = (pointerIcon != null) ?
+                            pointerIcon.getStyle() : PointerIcon.STYLE_DEFAULT;
 
-                    if (mPointerIconShape != pointerShape) {
-                        mPointerIconShape = pointerShape;
-                        final InputDevice inputDevice = event.getDevice();
-                        if (inputDevice != null) {
-                            inputDevice.setPointerShape(pointerShape);
+                    final InputDevice inputDevice = event.getDevice();
+                    if (inputDevice != null) {
+                        if (mPointerIconShape != pointerShape) {
+                            mPointerIconShape = pointerShape;
+                            if (mPointerIconShape != PointerIcon.STYLE_CUSTOM) {
+                                mCustomPointerIcon = null;
+                                inputDevice.setPointerShape(pointerShape);
+                            }
+                        }
+                        if (mPointerIconShape == PointerIcon.STYLE_CUSTOM &&
+                                !pointerIcon.equals(mCustomPointerIcon)) {
+                            mCustomPointerIcon = pointerIcon;
+                            inputDevice.setCustomPointerIcon(mCustomPointerIcon);
                         }
                     }
                 } else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 7a359e7..d7a98ab 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -29,6 +29,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.media.session.MediaController;
 import android.net.Uri;
@@ -247,12 +248,30 @@
 
     private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
 
+    /**
+     * Flag for letting the theme drive the color of the window caption controls. Use with
+     * {@link #setDecorCaptionShade(int)}. This is the default value.
+     */
+    public static final int DECOR_CAPTION_SHADE_AUTO = 0;
+    /**
+     * Flag for setting light-color controls on the window caption. Use with
+     * {@link #setDecorCaptionShade(int)}.
+     */
+    public static final int DECOR_CAPTION_SHADE_LIGHT = 1;
+    /**
+     * Flag for setting dark-color controls on the window caption. Use with
+     * {@link #setDecorCaptionShade(int)}.
+     */
+    public static final int DECOR_CAPTION_SHADE_DARK = 2;
+
     private final Context mContext;
 
     private TypedArray mWindowStyle;
     private Callback mCallback;
     private OnWindowDismissedCallback mOnWindowDismissedCallback;
     private WindowControllerCallback mWindowControllerCallback;
+    private RestrictedCaptionAreaListener mRestrictedCaptionAreaListener;
+    private Rect mRestrictedCaptionAreaRect;
     private WindowManager mWindowManager;
     private IBinder mAppToken;
     private String mAppName;
@@ -565,6 +584,18 @@
         int getWindowStackId() throws RemoteException;
     }
 
+    /**
+     * Callback for clients that want to be aware of where caption draws content.
+     */
+    public interface RestrictedCaptionAreaListener {
+        /**
+         * Called when the area where caption draws content changes.
+         *
+         * @param rect The area where caption content is positioned, relative to the top view.
+         */
+        void onRestrictedCaptionAreaChanged(Rect rect);
+    }
+
     public Window(Context context) {
         mContext = context;
         mFeatures = mLocalFeatures = getDefaultFeatures(context);
@@ -778,6 +809,16 @@
     }
 
     /**
+     * Set a callback for changes of area where caption will draw its content.
+     *
+     * @param listener Callback that will be called when the area changes.
+     */
+    public final void setRestrictedCaptionAreaListener(RestrictedCaptionAreaListener listener) {
+        mRestrictedCaptionAreaListener = listener;
+        mRestrictedCaptionAreaRect = listener != null ? new Rect() : null;
+    }
+
+    /**
      * Take ownership of this window's surface.  The window's view hierarchy
      * will no longer draw into the surface, though it will otherwise continue
      * to operate (such as for receiving input events).  The given SurfaceHolder
@@ -2040,5 +2081,35 @@
         return mOverlayWithDecorCaption;
     }
 
+    /** @hide */
+    public void notifyRestrictedCaptionAreaCallback(int left, int top, int right, int bottom) {
+        if (mRestrictedCaptionAreaListener != null) {
+            mRestrictedCaptionAreaRect.set(left, top, right, bottom);
+            mRestrictedCaptionAreaListener.onRestrictedCaptionAreaChanged(
+                    mRestrictedCaptionAreaRect);
+        }
+    }
 
+    /**
+     * Set what color should the caption controls be. By default the system will try to determine
+     * the color from the theme. You can overwrite this by using {@link #DECOR_CAPTION_SHADE_DARK}
+     * or {@link #DECOR_CAPTION_SHADE_DARK}.
+     */
+    public abstract void setDecorCaptionShade(int decorCaptionShade);
+
+    /**
+     * Set the drawable that is drawn underneath the caption during the resizing.
+     *
+     * During the resizing the caption might not be drawn fast enough to match the new dimensions.
+     * There is a second caption drawn underneath it that will be fast enough. By default the
+     * caption is constructed from the theme. You can provide a drawable, that will be drawn instead
+     * to better match your application.
+     */
+    public abstract void setResizingCaptionDrawable(Drawable drawable);
+
+    /**
+     * Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
+     * @hide
+     */
+    public abstract void onMultiWindowModeChanged();
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d6bc27c..2e884cc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1171,6 +1171,16 @@
          */
         public static final int PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY = 0x00004000;
 
+        /**
+         * Flag to indicate that this window is not expected to be replaced across
+         * configuration change triggered activity relaunches. In general the WindowManager
+         * expects Windows to be replaced after relaunch, and thus it will preserve their surfaces
+         * until the replacement is ready to show in order to prevent visual glitch. However
+         * some windows, such as PopupWindows expect to be cleared across configuration change,
+         * and thus should hint to the WindowManager that it should not wait for a replacement.
+         * @hide
+         */
+        public static final int PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH = 0x00008000;
 
         /**
          * Control flags that are private to the platform.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index b1a8479..01bfbb5 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -446,6 +446,13 @@
          */
         public void switchKeyboardLayout(int deviceId, int direction);
 
+        /**
+         * Switch the input method, to be precise, input method subtype.
+         *
+         * @param forwardDirection {@code true} to rotate in a forward direction.
+         */
+        public void switchInputMethod(boolean forwardDirection);
+
         public void shutdown(boolean confirm);
         public void rebootSafeMode(boolean confirm);
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 329d1b0..5e07347 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -54,6 +54,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -2209,7 +2210,7 @@
             p.println("  mCurrentTextBoxAttribute: null");
         }
         p.println("  mServedInputConnection=" + mServedInputConnection);
-        p.println("  mCompletions=" + mCompletions);
+        p.println("  mCompletions=" + Arrays.toString(mCompletions));
         p.println("  mCursorRect=" + mCursorRect);
         p.println("  mCursorSelStart=" + mCursorSelStart
                 + " mCursorSelEnd=" + mCursorSelEnd
diff --git a/core/java/android/view/inputmethod/InputMethodManagerInternal.java b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
index c22127b..ce9908c 100644
--- a/core/java/android/view/inputmethod/InputMethodManagerInternal.java
+++ b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
@@ -26,5 +26,10 @@
      * Called by the power manager to tell the input method manager whether it
      * should start watching for wake events.
      */
-    public void setInteractive(boolean interactive);
+    void setInteractive(boolean interactive);
+
+    /**
+     * Called by the window manager to let the input method manager rotate the input method.
+     */
+    void switchInputMethod(boolean forwardDirection);
 }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index fbaf51c..a42f4d9 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -50,6 +51,7 @@
  *
  * @attr ref android.R.styleable#InputMethod_Subtype_label
  * @attr ref android.R.styleable#InputMethod_Subtype_icon
+ * @attr ref android.R.styleable#InputMethod_Subtype_languageTag
  * @attr ref android.R.styleable#InputMethod_Subtype_imeSubtypeLocale
  * @attr ref android.R.styleable#InputMethod_Subtype_imeSubtypeMode
  * @attr ref android.R.styleable#InputMethod_Subtype_imeSubtypeExtraValue
@@ -60,6 +62,7 @@
  */
 public final class InputMethodSubtype implements Parcelable {
     private static final String TAG = InputMethodSubtype.class.getSimpleName();
+    private static final String LANGUAGE_TAG_NONE = "";
     private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
     private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
     // TODO: remove this
@@ -74,6 +77,7 @@
     private final int mSubtypeNameResId;
     private final int mSubtypeId;
     private final String mSubtypeLocale;
+    private final String mSubtypeLanguageTag;
     private final String mSubtypeMode;
     private final String mSubtypeExtraValue;
     private volatile HashMap<String, String> mExtraValueHashMapCache;
@@ -171,6 +175,15 @@
         private String mSubtypeLocale = "";
 
         /**
+         * @param languageTag is the BCP-47 Language Tag supported by this subtype.
+         */
+        public InputMethodSubtypeBuilder setLanguageTag(String languageTag) {
+            mSubtypeLanguageTag = languageTag == null ? LANGUAGE_TAG_NONE : languageTag;
+            return this;
+        }
+        private String mSubtypeLanguageTag = LANGUAGE_TAG_NONE;
+
+        /**
          * @param subtypeMode is the mode supported by this subtype.
          */
         public InputMethodSubtypeBuilder setSubtypeMode(String subtypeMode) {
@@ -271,6 +284,7 @@
         mSubtypeNameResId = builder.mSubtypeNameResId;
         mSubtypeIconResId = builder.mSubtypeIconResId;
         mSubtypeLocale = builder.mSubtypeLocale;
+        mSubtypeLanguageTag = builder.mSubtypeLanguageTag;
         mSubtypeMode = builder.mSubtypeMode;
         mSubtypeExtraValue = builder.mSubtypeExtraValue;
         mIsAuxiliary = builder.mIsAuxiliary;
@@ -291,6 +305,8 @@
         s = source.readString();
         mSubtypeLocale = s != null ? s : "";
         s = source.readString();
+        mSubtypeLanguageTag = s != null ? s : LANGUAGE_TAG_NONE;
+        s = source.readString();
         mSubtypeMode = s != null ? s : "";
         s = source.readString();
         mSubtypeExtraValue = s != null ? s : "";
@@ -318,21 +334,38 @@
     /**
      * @return The locale of the subtype. This method returns the "locale" string parameter passed
      * to the constructor.
+     *
+     * @deprecated Use {@link #getLanguageTag()} instead.
      */
+    @Deprecated
+    @NonNull
     public String getLocale() {
         return mSubtypeLocale;
     }
 
     /**
-     * @return The normalized {@link Locale} object of the subtype. The returned locale may or may
-     * not equal to "locale" string parameter passed to the constructor.
+     * @return the BCP-47 Language Tag of the subtype.  Returns an empty string when no Language Tag
+     * is specified.
      *
-     * <p>TODO: Consider to make this a public API.</p>
+     * @see Locale#forLanguageTag(String)
+     */
+    @NonNull
+    public String getLanguageTag() {
+        return mSubtypeLanguageTag;
+    }
+
+    /**
+     * @return {@link Locale} constructed from {@link #getLanguageTag()}. If the Language Tag is not
+     * specified, then try to construct from {@link #getLocale()}
+     *
+     * <p>TODO: Consider to make this a public API, or move this to support lib.</p>
      * @hide
      */
     @Nullable
     public Locale getLocaleObject() {
-        // TODO: Move the following method from InputMethodUtils to InputMethodSubtype.
+        if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
+            return Locale.forLanguageTag(mSubtypeLanguageTag);
+        }
         return InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
     }
 
@@ -476,13 +509,14 @@
                 return (subtype.hashCode() == hashCode());
             }
             return (subtype.hashCode() == hashCode())
-                && (subtype.getLocale().equals(getLocale()))
-                && (subtype.getMode().equals(getMode()))
-                && (subtype.getExtraValue().equals(getExtraValue()))
-                && (subtype.isAuxiliary() == isAuxiliary())
-                && (subtype.overridesImplicitlyEnabledSubtype()
-                        == overridesImplicitlyEnabledSubtype())
-                && (subtype.isAsciiCapable() == isAsciiCapable());
+                    && (subtype.getLocale().equals(getLocale()))
+                    && (subtype.getLanguageTag().equals(getLanguageTag()))
+                    && (subtype.getMode().equals(getMode()))
+                    && (subtype.getExtraValue().equals(getExtraValue()))
+                    && (subtype.isAuxiliary() == isAuxiliary())
+                    && (subtype.overridesImplicitlyEnabledSubtype()
+                            == overridesImplicitlyEnabledSubtype())
+                    && (subtype.isAsciiCapable() == isAsciiCapable());
         }
         return false;
     }
@@ -497,6 +531,7 @@
         dest.writeInt(mSubtypeNameResId);
         dest.writeInt(mSubtypeIconResId);
         dest.writeString(mSubtypeLocale);
+        dest.writeString(mSubtypeLanguageTag);
         dest.writeString(mSubtypeMode);
         dest.writeString(mSubtypeExtraValue);
         dest.writeInt(mIsAuxiliary ? 1 : 0);
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 491de78..471b6d4 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -117,6 +117,8 @@
                             a.getString(com.android.internal.R.styleable
                                     .SpellChecker_Subtype_subtypeLocale),
                             a.getString(com.android.internal.R.styleable
+                                    .SpellChecker_Subtype_languageTag),
+                            a.getString(com.android.internal.R.styleable
                                     .SpellChecker_Subtype_subtypeExtraValue),
                             a.getInt(com.android.internal.R.styleable
                                     .SpellChecker_Subtype_subtypeId, 0));
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index f2b03cc..df33698 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.inputmethod.InputMethodUtils;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -40,6 +41,7 @@
  * @see SpellCheckerInfo
  *
  * @attr ref android.R.styleable#SpellChecker_Subtype_label
+ * @attr ref android.R.styleable#SpellChecker_Subtype_languageTag
  * @attr ref android.R.styleable#SpellChecker_Subtype_subtypeLocale
  * @attr ref android.R.styleable#SpellChecker_Subtype_subtypeExtraValue
  * @attr ref android.R.styleable#SpellChecker_Subtype_subtypeId
@@ -49,11 +51,13 @@
     private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
     private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
     private static final int SUBTYPE_ID_NONE = 0;
+    private static final String SUBTYPE_LANGUAGE_TAG_NONE = "";
 
     private final int mSubtypeId;
     private final int mSubtypeHashCode;
     private final int mSubtypeNameResId;
     private final String mSubtypeLocale;
+    private final String mSubtypeLanguageTag;
     private final String mSubtypeExtraValue;
     private HashMap<String, String> mExtraValueHashMapCache;
 
@@ -66,14 +70,17 @@
      *
      * @param nameId The name of the subtype
      * @param locale The locale supported by the subtype
+     * @param languageTag The BCP-47 Language Tag associated with this subtype.
      * @param extraValue The extra value of the subtype
      * @param subtypeId The subtype ID that is supposed to be stable during package update.
      *
      * @hide
      */
-    public SpellCheckerSubtype(int nameId, String locale, String extraValue, int subtypeId) {
+    public SpellCheckerSubtype(int nameId, String locale, String languageTag, String extraValue,
+            int subtypeId) {
         mSubtypeNameResId = nameId;
         mSubtypeLocale = locale != null ? locale : "";
+        mSubtypeLanguageTag = languageTag != null ? languageTag : SUBTYPE_LANGUAGE_TAG_NONE;
         mSubtypeExtraValue = extraValue != null ? extraValue : "";
         mSubtypeId = subtypeId;
         mSubtypeHashCode = mSubtypeId != SUBTYPE_ID_NONE ?
@@ -91,7 +98,7 @@
      * to instantiate {@link SpellCheckerSubtype} object.
      */
     public SpellCheckerSubtype(int nameId, String locale, String extraValue) {
-        this(nameId, locale, extraValue, SUBTYPE_ID_NONE);
+        this(nameId, locale, SUBTYPE_LANGUAGE_TAG_NONE, extraValue, SUBTYPE_ID_NONE);
     }
 
     SpellCheckerSubtype(Parcel source) {
@@ -100,6 +107,8 @@
         s = source.readString();
         mSubtypeLocale = s != null ? s : "";
         s = source.readString();
+        mSubtypeLanguageTag = s != null ? s : "";
+        s = source.readString();
         mSubtypeExtraValue = s != null ? s : "";
         mSubtypeId = source.readInt();
         mSubtypeHashCode = mSubtypeId != SUBTYPE_ID_NONE ?
@@ -115,12 +124,27 @@
 
     /**
      * @return the locale of the subtype
+     *
+     * @deprecated Use {@link #getLanguageTag()} instead.
      */
+    @Deprecated
+    @NonNull
     public String getLocale() {
         return mSubtypeLocale;
     }
 
     /**
+     * @return the BCP-47 Language Tag of the subtype.  Returns an empty string when no Language Tag
+     * is specified.
+     *
+     * @see Locale#forLanguageTag(String)
+     */
+    @NonNull
+    public String getLanguageTag() {
+        return mSubtypeLanguageTag;
+    }
+
+    /**
      * @return the extra value of the subtype
      */
     public String getExtraValue() {
@@ -182,20 +206,24 @@
             return (subtype.hashCode() == hashCode())
                     && (subtype.getNameResId() == getNameResId())
                     && (subtype.getLocale().equals(getLocale()))
+                    && (subtype.getLanguageTag().equals(getLanguageTag()))
                     && (subtype.getExtraValue().equals(getExtraValue()));
         }
         return false;
     }
 
     /**
-     * @return The normalized {@link Locale} object of the subtype. The returned locale may or may
-     * not equal to "locale" string parameter passed to the constructor.
+     * @return {@link Locale} constructed from {@link #getLanguageTag()}. If the Language Tag is not
+     * specified, then try to construct from {@link #getLocale()}
      *
-     * <p>TODO: Consider to make this a public API.</p>
+     * <p>TODO: Consider to make this a public API, or move this to support lib.</p>
      * @hide
      */
     @Nullable
     public Locale getLocaleObject() {
+        if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
+            return Locale.forLanguageTag(mSubtypeLanguageTag);
+        }
         return InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
     }
 
@@ -234,6 +262,7 @@
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         dest.writeInt(mSubtypeNameResId);
         dest.writeString(mSubtypeLocale);
+        dest.writeString(mSubtypeLanguageTag);
         dest.writeString(mSubtypeExtraValue);
         dest.writeInt(mSubtypeId);
     }
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index a77459b..89d5d69 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -16,6 +16,10 @@
 
 package android.webkit;
 
+import android.content.pm.PackageInfo;
+import android.webkit.WebViewProviderInfo;
+import android.webkit.WebViewProviderResponse;
+
 /**
  * Private service to wait for the updatable WebView to be ready for use.
  * @hide
@@ -25,12 +29,28 @@
     /**
      * Used by the relro file creator to notify the service that it's done.
      */
-    void notifyRelroCreationCompleted(boolean is64Bit, boolean success);
+    void notifyRelroCreationCompleted();
 
     /**
      * Used by WebViewFactory to block loading of WebView code until
-     * preparations are complete.
+     * preparations are complete. Returns the package used as WebView provider.
      */
-    void waitForRelroCreationCompleted(boolean is64Bit);
+    WebViewProviderResponse waitForAndGetProvider();
 
+    /**
+     * DevelopmentSettings uses this to notify WebViewUpdateService that a
+     * new provider has been selected by the user.
+     */
+    void changeProviderAndSetting(String newProvider);
+
+    /**
+     * DevelopmentSettings uses this to get the current available WebView
+     * providers (to display as choices to the user).
+     */
+    WebViewProviderInfo[] getValidWebViewPackages();
+
+    /**
+     * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
+     */
+    String getCurrentWebViewPackageName();
 }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 229011d..01d1566 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -24,6 +24,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
@@ -31,20 +32,27 @@
 import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
 
+import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
 
 import dalvik.system.VMRuntime;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 /**
  * Top level factory, used creating all the main WebView implementation classes.
  *
@@ -83,6 +91,8 @@
     public static final int LIBLOAD_SUCCESS = 0;
     public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1;
     public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2;
+
+    // error codes for waiting for WebView preparation
     public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3;
     public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4;
 
@@ -91,57 +101,95 @@
     public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6;
     public static final int LIBLOAD_FAILED_JNI_CALL = 7;
 
-    private static class MissingWebViewPackageException extends AndroidRuntimeException {
+    // more error codes for waiting for WebView preparation
+    public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8;
+    public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9;
+
+    private static String getWebViewPreparationErrorReason(int error) {
+        switch (error) {
+            case LIBLOAD_FAILED_WAITING_FOR_RELRO:
+                return "Time out waiting for Relro files being created";
+            case LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES:
+                return "No WebView installed";
+            case LIBLOAD_WEBVIEW_BEING_REPLACED:
+                return "Time out waiting for WebView to be replaced";
+            case LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN:
+                return "Crashed for unknown reason";
+        }
+        return "Unknown";
+    }
+
+    /**
+     * @hide
+     */
+    public static class MissingWebViewPackageException extends AndroidRuntimeException {
         public MissingWebViewPackageException(String message) { super(message); }
         public MissingWebViewPackageException(Exception e) { super(e); }
     }
 
-    /** @hide */
-    public static String[] getWebViewPackageNames() {
-        return AppGlobals.getInitialApplication().getResources().getStringArray(
-                com.android.internal.R.array.config_webViewPackageNames);
+    private static String TAG_START = "webviewproviders";
+    private static String TAG_WEBVIEW_PROVIDER = "webviewprovider";
+    private static String TAG_PACKAGE_NAME = "packageName";
+    private static String TAG_DESCRIPTION = "description";
+    private static String TAG_SIGNATURE = "signature";
+
+    /**
+     * Returns all packages declared in the framework resources as potential WebView providers.
+     * @hide
+     * */
+    public static WebViewProviderInfo[] getWebViewPackages() {
+        XmlResourceParser parser = null;
+        List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
+        try {
+            parser = AppGlobals.getInitialApplication().getResources().getXml(
+                    com.android.internal.R.xml.config_webview_packages);
+            XmlUtils.beginDocument(parser, TAG_START);
+            while(true) {
+                XmlUtils.nextElement(parser);
+                String element = parser.getName();
+                if (element == null) {
+                    break;
+                }
+                if (element.equals(TAG_WEBVIEW_PROVIDER)) {
+                    String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
+                    if (packageName == null) {
+                        throw new MissingWebViewPackageException(
+                                "WebView provider in framework resources missing package name");
+                    }
+                    String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
+                    if (description == null) {
+                        throw new MissingWebViewPackageException(
+                                "WebView provider in framework resources missing description");
+                    }
+                    String signature = parser.getAttributeValue(null, TAG_SIGNATURE);
+                    webViewProviders.add(
+                            new WebViewProviderInfo(packageName, description, signature));
+                }
+                else {
+                    Log.e(LOGTAG, "Found an element that is not a webview provider");
+                }
+            }
+        } catch(XmlPullParserException e) {
+            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+        } catch(IOException e) {
+            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
     }
 
+
     // TODO (gsennton) remove when committing webview xts test change
     public static String getWebViewPackageName() {
-        String[] webViewPackageNames = getWebViewPackageNames();
-        return webViewPackageNames[webViewPackageNames.length-1];
+        WebViewProviderInfo[] providers = getWebViewPackages();
+        return providers[0].packageName;
     }
 
     /**
-     * Return the package info of the first package in the webview priority list that contains
-     * webview.
-     *
      * @hide
      */
-    public static PackageInfo findPreferredWebViewPackage() {
-        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-
-        for (String packageName : getWebViewPackageNames()) {
-            try {
-                PackageInfo packageInfo = pm.getPackageInfo(packageName,
-                    PackageManager.GET_META_DATA);
-                ApplicationInfo applicationInfo = packageInfo.applicationInfo;
-
-                // If the correct flag is set the package contains webview.
-                if (getWebViewLibrary(applicationInfo) != null) {
-                    return packageInfo;
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-            }
-        }
-        throw new MissingWebViewPackageException("Could not find a loadable WebView package");
-    }
-
-    // throws MissingWebViewPackageException
-    private static ApplicationInfo getWebViewApplicationInfo() {
-        if (sPackageInfo == null)
-            return findPreferredWebViewPackage().applicationInfo;
-        else
-            return sPackageInfo.applicationInfo;
-    }
-
-    private static String getWebViewLibrary(ApplicationInfo ai) {
+    public static String getWebViewLibrary(ApplicationInfo ai) {
         if (ai.metaData != null)
             return ai.metaData.getString("com.android.webview.WebViewLibrary");
         return null;
@@ -156,16 +204,14 @@
      * name is the same as the one providing the webview.
      */
     public static int loadWebViewNativeLibraryFromPackage(String packageName) {
-        try {
-            sPackageInfo = findPreferredWebViewPackage();
-        } catch (MissingWebViewPackageException e) {
-            return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
+        int ret = waitForProviderAndSetPackageInfo();
+        if (ret != LIBLOAD_SUCCESS) {
+            return ret;
         }
+        if (!sPackageInfo.packageName.equals(packageName))
+            return LIBLOAD_WRONG_PACKAGE_NAME;
 
-        if (packageName != null && packageName.equals(sPackageInfo.packageName)) {
-            return loadNativeLibrary();
-        }
-        return LIBLOAD_WRONG_PACKAGE_NAME;
+        return loadNativeLibrary();
     }
 
     static WebViewFactoryProvider getProvider() {
@@ -207,17 +253,45 @@
     private static Class<WebViewFactoryProvider> getProviderClass() {
         try {
             // First fetch the package info so we can log the webview package version.
-            sPackageInfo = findPreferredWebViewPackage();
+            int res = waitForProviderAndSetPackageInfo();
+            if (res != LIBLOAD_SUCCESS) {
+                throw new MissingWebViewPackageException(
+                        "Failed to load WebView provider, error: "
+                        + getWebViewPreparationErrorReason(res));
+            }
             Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
                 sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
 
+            Application initialApplication = AppGlobals.getInitialApplication();
+            Context webViewContext = null;
+            try {
+                // Construct a package context to load the Java code into the current app.
+                // This is done as early as possible since by constructing a package context we
+                // register the WebView package as a dependency for the current application so that
+                // when the WebView package is updated this application will be killed.
+                webViewContext = initialApplication.createPackageContext(
+                        sPackageInfo.packageName,
+                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new MissingWebViewPackageException(e);
+            }
+
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
             loadNativeLibrary();
             Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
-                return getChromiumProviderClass();
+                initialApplication.getAssets().addAssetPathAsSharedLibrary(
+                        webViewContext.getApplicationInfo().sourceDir);
+                ClassLoader clazzLoader = webViewContext.getClassLoader();
+                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
+                try {
+                    return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
+                            true, clazzLoader);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+                }
             } catch (ClassNotFoundException e) {
                 Log.e(LOGTAG, "error loading provider", e);
                 throw new AndroidRuntimeException(e);
@@ -239,30 +313,6 @@
         }
     }
 
-    // throws MissingWebViewPackageException
-    private static Class<WebViewFactoryProvider> getChromiumProviderClass()
-            throws ClassNotFoundException {
-        Application initialApplication = AppGlobals.getInitialApplication();
-        try {
-            // Construct a package context to load the Java code into the current app.
-            Context webViewContext = initialApplication.createPackageContext(
-                    sPackageInfo.packageName,
-                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
-            initialApplication.getAssets().addAssetPathAsSharedLibrary(
-                    webViewContext.getApplicationInfo().sourceDir);
-            ClassLoader clazzLoader = webViewContext.getClassLoader();
-            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
-            try {
-                return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
-                                                                     clazzLoader);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new MissingWebViewPackageException(e);
-        }
-    }
-
     /**
      * Perform any WebView loading preparations that must happen in the zygote.
      * Currently, this means allocating address space to load the real JNI library later.
@@ -289,44 +339,34 @@
         }
     }
 
-    /**
-     * Perform any WebView loading preparations that must happen at boot from the system server,
-     * after the package manager has started or after an update to the webview is installed.
-     * This must be called in the system server.
-     * Currently, this means spawning the child processes which will create the relro files.
-     */
-    public static void prepareWebViewInSystemServer() {
-        String[] nativePaths = null;
-        try {
-            nativePaths = getWebViewNativeLibraryPaths();
-        } catch (Throwable t) {
-            // Log and discard errors at this stage as we must not crash the system server.
-            Log.e(LOGTAG, "error preparing webview native library", t);
-        }
-        prepareWebViewInSystemServer(nativePaths);
-    }
-
-    private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
+    private static int prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
         if (DEBUG) Log.v(LOGTAG, "creating relro files");
+        int numRelros = 0;
 
         // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
         // unexpected values will be handled there to ensure that we trigger notifying any process
-        // waiting on relreo creation.
+        // waiting on relro creation.
         if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
             if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
             createRelroFile(false /* is64Bit */, nativeLibraryPaths);
+            numRelros++;
         }
 
         if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
             if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
             createRelroFile(true /* is64Bit */, nativeLibraryPaths);
+            numRelros++;
         }
+        return numRelros;
     }
 
-    public static void onWebViewUpdateInstalled() {
+    /**
+     * @hide
+     */
+    public static int onWebViewProviderChanged(PackageInfo packageInfo) {
         String[] nativeLibs = null;
         try {
-            nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
+            nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo);
             if (nativeLibs != null) {
                 long newVmSize = 0L;
 
@@ -373,7 +413,7 @@
             // Log and discard errors at this stage as we must not crash the system server.
             Log.e(LOGTAG, "error preparing webview native library", t);
         }
-        prepareWebViewInSystemServer(nativeLibs);
+        return prepareWebViewInSystemServer(nativeLibs);
     }
 
     // throws MissingWebViewPackageException
@@ -397,8 +437,8 @@
     }
 
     // throws MissingWebViewPackageException
-    private static String[] getWebViewNativeLibraryPaths() {
-        ApplicationInfo ai = getWebViewApplicationInfo();
+    private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo) {
+        ApplicationInfo ai = packageInfo.applicationInfo;
         final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
 
         String path32;
@@ -460,7 +500,7 @@
             public void run() {
                 try {
                     Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
-                    getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
+                    getUpdateService().notifyRelroCreationCompleted();
                 } catch (RemoteException e) {
                     Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
                 }
@@ -508,7 +548,7 @@
             } finally {
                 // We must do our best to always notify the update service, even if something fails.
                 try {
-                    getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
+                    getUpdateService().notifyRelroCreationCompleted();
                 } catch (RemoteException e) {
                     Log.e(LOGTAG, "error notifying update service", e);
                 }
@@ -521,35 +561,38 @@
         }
     }
 
+    private static int waitForProviderAndSetPackageInfo() {
+        WebViewProviderResponse response = null;
+        try {
+            response =
+                getUpdateService().waitForAndGetProvider();
+            if (response.status == WebViewFactory.LIBLOAD_SUCCESS)
+                sPackageInfo = response.packageInfo;
+        } catch (RemoteException e) {
+            Log.e(LOGTAG, "error waiting for relro creation", e);
+            return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
+        }
+        return response.status;
+    }
+
+    // Assumes that we have waited for relro creation and set sPackageInfo
     private static int loadNativeLibrary() {
         if (!sAddressSpaceReserved) {
             Log.e(LOGTAG, "can't load with relro file; address space not reserved");
             return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
         }
 
-        try {
-            getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
-        } catch (RemoteException e) {
-            Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
-            return LIBLOAD_FAILED_WAITING_FOR_RELRO;
+        String[] args = getWebViewNativeLibraryPaths(sPackageInfo);
+        int result = nativeLoadWithRelroFile(args[0] /* path32 */,
+                                                 args[1] /* path64 */,
+                                                 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+                                                 CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+        if (result != LIBLOAD_SUCCESS) {
+            Log.w(LOGTAG, "failed to load with relro file, proceeding without");
+        } else if (DEBUG) {
+            Log.v(LOGTAG, "loaded with relro file");
         }
-
-        try {
-            String[] args = getWebViewNativeLibraryPaths();
-            int result = nativeLoadWithRelroFile(args[0] /* path32 */,
-                                                     args[1] /* path64 */,
-                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
-                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
-            if (result != LIBLOAD_SUCCESS) {
-                Log.w(LOGTAG, "failed to load with relro file, proceeding without");
-            } else if (DEBUG) {
-                Log.v(LOGTAG, "loaded with relro file");
-            }
-            return result;
-        } catch (MissingWebViewPackageException e) {
-            Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
-            return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
-        }
+        return result;
     }
 
     private static IWebViewUpdateService getUpdateService() {
diff --git a/core/java/android/webkit/WebViewProviderInfo.aidl b/core/java/android/webkit/WebViewProviderInfo.aidl
new file mode 100644
index 0000000..82e5a79
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+parcelable WebViewProviderInfo;
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
new file mode 100644
index 0000000..d5e3a230
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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.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
+     */
+    public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
+        public WebViewPackageNotFoundException(String message) { super(message); }
+        public WebViewPackageNotFoundException(Exception e) { super(e); }
+    }
+
+    public WebViewProviderInfo(String packageName, String description, String signature) {
+        this.packageName = packageName;
+        this.description = description;
+        this.signature = signature;
+    }
+
+    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 (signature == null)
+                return getPackageInfo().applicationInfo.isSystemApp();
+
+            packageSignatures = getPackageInfo().signatures;
+        } catch (WebViewPackageNotFoundException e) {
+            return false;
+        }
+        if (packageSignatures.length != 1)
+            return false;
+        final byte[] releaseSignature = Base64.decode(signature, Base64.DEFAULT);
+        return Arrays.equals(releaseSignature, packageSignatures[0].toByteArray());
+    }
+
+    /**
+     * 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;
+    }
+
+    public PackageInfo getPackageInfo() {
+        if (packageInfo == null) {
+            try {
+                PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+                packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new WebViewPackageNotFoundException(e);
+            }
+        }
+        return packageInfo;
+    }
+
+    // aidl stuff
+    public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
+        new Parcelable.Creator<WebViewProviderInfo>() {
+            public WebViewProviderInfo createFromParcel(Parcel in) {
+                return new WebViewProviderInfo(in);
+            }
+
+            public WebViewProviderInfo[] newArray(int size) {
+                return new WebViewProviderInfo[size];
+            }
+        };
+
+    private WebViewProviderInfo(Parcel in) {
+        packageName = in.readString();
+        description = in.readString();
+        signature = in.readString();
+        packageInfo = null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(packageName);
+        out.writeString(description);
+        out.writeString(signature);
+    }
+
+    // fields read from framework resource
+    public String packageName;
+    public String description;
+
+    private String signature;
+
+    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;
+}
+
diff --git a/core/java/android/webkit/WebViewProviderResponse.aidl b/core/java/android/webkit/WebViewProviderResponse.aidl
new file mode 100644
index 0000000..9c884cc
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+parcelable WebViewProviderResponse;
diff --git a/core/java/android/webkit/WebViewProviderResponse.java b/core/java/android/webkit/WebViewProviderResponse.java
new file mode 100644
index 0000000..f5e09e2
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderResponse.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.content.pm.PackageInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class WebViewProviderResponse implements Parcelable {
+
+    public WebViewProviderResponse(PackageInfo packageInfo, int status) {
+        this.packageInfo = packageInfo;
+        this.status = status;
+    }
+
+    // aidl stuff
+    public static final Parcelable.Creator<WebViewProviderResponse> CREATOR =
+        new Parcelable.Creator<WebViewProviderResponse>() {
+            public WebViewProviderResponse createFromParcel(Parcel in) {
+                return new WebViewProviderResponse(in);
+            }
+
+            public WebViewProviderResponse[] newArray(int size) {
+                return new WebViewProviderResponse[size];
+            }
+        };
+
+    private WebViewProviderResponse(Parcel in) {
+        packageInfo = in.readTypedObject(PackageInfo.CREATOR);
+        status = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeTypedObject(packageInfo, flags);
+        out.writeInt(status);
+    }
+
+    PackageInfo packageInfo;
+    int status;
+}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 5146bc6..2d1f855 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -75,6 +75,7 @@
 import android.view.DisplayListCanvas;
 import android.view.DragEvent;
 import android.view.Gravity;
+import android.view.InputDevice;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -229,7 +230,14 @@
     // Set when this TextView gained focus with some text selected. Will start selection mode.
     boolean mCreatedWithASelection;
 
-    boolean mDoubleTap = false;
+    // Indicates the current tap state (first tap, double tap, or triple click).
+    private int mTapState = TAP_STATE_INITIAL;
+    private long mLastTouchUpTime = 0;
+    private static final int TAP_STATE_INITIAL = 0;
+    private static final int TAP_STATE_FIRST_TAP = 1;
+    private static final int TAP_STATE_DOUBLE_TAP = 2;
+    // Only for mouse input.
+    private static final int TAP_STATE_TRIPLE_CLICK = 3;
 
     private Runnable mInsertionActionModeRunnable;
 
@@ -769,20 +777,12 @@
         return retOffset;
     }
 
-    /**
-     * Adjusts selection to the word under last touch offset. Return true if the operation was
-     * successfully performed.
-     */
-    private boolean selectCurrentWord() {
-        if (!mTextView.canSelectText()) {
-            return false;
-        }
-
+    private boolean needsToSelectAllToSelectWordOrParagraph() {
         if (mTextView.hasPasswordTransformationMethod()) {
             // Always select all on a password field.
             // Cut/copy menu entries are not available for passwords, but being able to select all
             // is however useful to delete or paste to replace the entire content.
-            return mTextView.selectAllText();
+            return true;
         }
 
         int inputType = mTextView.getInputType();
@@ -797,6 +797,21 @@
                 variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
                 variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ||
                 variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Adjusts selection to the word under last touch offset. Return true if the operation was
+     * successfully performed.
+     */
+    private boolean selectCurrentWord() {
+        if (!mTextView.canSelectText()) {
+            return false;
+        }
+
+        if (needsToSelectAllToSelectWordOrParagraph()) {
             return mTextView.selectAllText();
         }
 
@@ -805,8 +820,8 @@
         final int maxOffset = TextUtils.unpackRangeEndFromLong(lastTouchOffsets);
 
         // Safety check in case standard touch event handling has been bypassed
-        if (minOffset < 0 || minOffset >= mTextView.getText().length()) return false;
-        if (maxOffset < 0 || maxOffset >= mTextView.getText().length()) return false;
+        if (minOffset < 0 || minOffset > mTextView.getText().length()) return false;
+        if (maxOffset < 0 || maxOffset > mTextView.getText().length()) return false;
 
         int selectionStart, selectionEnd;
 
@@ -839,6 +854,63 @@
         return selectionEnd > selectionStart;
     }
 
+    /**
+     * Adjusts selection to the paragraph under last touch offset. Return true if the operation was
+     * successfully performed.
+     */
+    private boolean selectCurrentParagraph() {
+        if (!mTextView.canSelectText()) {
+            return false;
+        }
+
+        if (needsToSelectAllToSelectWordOrParagraph()) {
+            return mTextView.selectAllText();
+        }
+
+        long lastTouchOffsets = getLastTouchOffsets();
+        final int minLastTouchOffset = TextUtils.unpackRangeStartFromLong(lastTouchOffsets);
+        final int maxLastTouchOffset = TextUtils.unpackRangeEndFromLong(lastTouchOffsets);
+
+        final long paragraphsRange = getParagraphsRange(minLastTouchOffset, maxLastTouchOffset);
+        final int start = TextUtils.unpackRangeStartFromLong(paragraphsRange);
+        final int end = TextUtils.unpackRangeEndFromLong(paragraphsRange);
+        if (start < end) {
+            Selection.setSelection((Spannable) mTextView.getText(), start, end);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get the minimum range of paragraphs that contains startOffset and endOffset.
+     */
+    private long getParagraphsRange(int startOffset, int endOffset) {
+        final Layout layout = mTextView.getLayout();
+        if (layout == null) {
+            return TextUtils.packRangeInLong(-1, -1);
+        }
+        final CharSequence text = mTextView.getText();
+        int minLine = layout.getLineForOffset(startOffset);
+        // Search paragraph start.
+        while (minLine > 0) {
+            final int prevLineEndOffset = layout.getLineEnd(minLine - 1);
+            if (text.charAt(prevLineEndOffset - 1) == '\n') {
+                break;
+            }
+            minLine--;
+        }
+        int maxLine = layout.getLineForOffset(endOffset);
+        // Search paragraph end.
+        while (maxLine < layout.getLineCount() - 1) {
+            final int lineEndOffset = layout.getLineEnd(maxLine);
+            if (text.charAt(lineEndOffset - 1) == '\n') {
+                break;
+            }
+            maxLine++;
+        }
+        return TextUtils.packRangeInLong(layout.getLineStart(minLine), layout.getLineEnd(maxLine));
+    }
+
     void onLocaleChanged() {
         // Will be re-created on demand in getWordIterator with the proper new locale
         mWordIterator = null;
@@ -1219,7 +1291,31 @@
         }
     }
 
+    private void updateTapState(MotionEvent event) {
+        final int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
+            final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
+            // Detect double tap and triple click.
+            if (((mTapState == TAP_STATE_FIRST_TAP)
+                    || ((mTapState == TAP_STATE_DOUBLE_TAP) && isMouse))
+                        && (SystemClock.uptimeMillis() - mLastTouchUpTime) <=
+                                ViewConfiguration.getDoubleTapTimeout()) {
+                if (mTapState == TAP_STATE_FIRST_TAP) {
+                    mTapState = TAP_STATE_DOUBLE_TAP;
+                } else {
+                    mTapState = TAP_STATE_TRIPLE_CLICK;
+                }
+            } else {
+                mTapState = TAP_STATE_FIRST_TAP;
+            }
+        }
+        if (action == MotionEvent.ACTION_UP) {
+            mLastTouchUpTime = SystemClock.uptimeMillis();
+        }
+    }
+
     void onTouchEvent(MotionEvent event) {
+        updateTapState(event);
         updateFloatingToolbarVisibility(event);
 
         if (hasSelectionController()) {
@@ -1773,7 +1869,8 @@
         stopTextActionMode();
         mPreserveDetachedSelection = false;
 
-        getSelectionController().enterDrag();
+        getSelectionController().enterDrag(
+                SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_WORD);
         return true;
     }
 
@@ -3777,30 +3874,6 @@
             }
         }
 
-        public void showAtLocation(int offset) {
-            // TODO - investigate if there's a better way to show the handles
-            // after the drag accelerator has occured.
-            int[] tmpCords = new int[2];
-            mTextView.getLocationInWindow(tmpCords);
-
-            Layout layout = mTextView.getLayout();
-            int posX = tmpCords[0];
-            int posY = tmpCords[1];
-
-            final int line = layout.getLineForOffset(offset);
-
-            int startX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f
-                    - mHotspotX - getHorizontalOffset() + getCursorOffset());
-            int startY = layout.getLineBottom(line);
-
-            // Take TextView's padding and scroll into account.
-            startX += mTextView.viewportToContentHorizontalOffset();
-            startY += mTextView.viewportToContentVerticalOffset();
-
-            mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
-                    startX + posX, startY + posY);
-        }
-
         @Override
         protected void onDraw(Canvas c) {
             final int drawWidth = mDrawable.getIntrinsicWidth();
@@ -3933,13 +4006,16 @@
 
             // Cancel the single tap delayed runnable.
             if (mInsertionActionModeRunnable != null
-                    && (mDoubleTap || isCursorInsideEasyCorrectionSpan())) {
+                    && ((mTapState == TAP_STATE_DOUBLE_TAP)
+                            || (mTapState == TAP_STATE_TRIPLE_CLICK)
+                            || isCursorInsideEasyCorrectionSpan())) {
                 mTextView.removeCallbacks(mInsertionActionModeRunnable);
             }
 
             // Prepare and schedule the single tap runnable to run exactly after the double tap
             // timeout has passed.
-            if (!mDoubleTap && !isCursorInsideEasyCorrectionSpan()
+            if ((mTapState != TAP_STATE_DOUBLE_TAP) && (mTapState != TAP_STATE_TRIPLE_CLICK)
+                    && !isCursorInsideEasyCorrectionSpan()
                     && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) {
                 if (mTextActionMode == null) {
                     if (mInsertionActionModeRunnable == null) {
@@ -4223,10 +4299,15 @@
 
             boolean isExpanding;
             final float xDiff = x - mPrevX;
-            if (atRtl == isStartHandle()) {
-                isExpanding = xDiff > 0 || currLine > mPreviousLineTouched;
+            if (isStartHandle()) {
+                isExpanding = currLine < mPreviousLineTouched;
             } else {
-                isExpanding = xDiff < 0 || currLine < mPreviousLineTouched;
+                isExpanding = currLine > mPreviousLineTouched;
+            }
+            if (atRtl == isStartHandle()) {
+                isExpanding |= xDiff > 0;
+            } else {
+                isExpanding |= xDiff < 0;
             }
 
             if (mTextView.getHorizontallyScrolling()) {
@@ -4492,14 +4573,24 @@
 
         // Where the user first starts the drag motion.
         private int mStartOffset = -1;
-        // Indicates whether the user is selecting text and using the drag accelerator.
-        private boolean mDragAcceleratorActive;
+
         private boolean mHaventMovedEnoughToStartDrag;
         // The line that a selection happened most recently with the drag accelerator.
         private int mLineSelectionIsOn = -1;
         // Whether the drag accelerator has selected past the initial line.
         private boolean mSwitchedLines = false;
 
+        // Indicates the drag accelerator mode that the user is currently using.
+        private int mDragAcceleratorMode = DRAG_ACCELERATOR_MODE_INACTIVE;
+        // Drag accelerator is inactive.
+        private static final int DRAG_ACCELERATOR_MODE_INACTIVE = 0;
+        // Character based selection by dragging. Only for mouse.
+        private static final int DRAG_ACCELERATOR_MODE_CHARACTER = 1;
+        // Word based selection by dragging. Enabled after long pressing or double tapping.
+        private static final int DRAG_ACCELERATOR_MODE_WORD = 2;
+        // Paragraph based selection by dragging. Enabled after mouse triple click.
+        private static final int DRAG_ACCELERATOR_MODE_PARAGRAPH = 3;
+
         SelectionModifierCursorController() {
             resetTouchOffsets();
         }
@@ -4510,7 +4601,6 @@
             }
             initDrawables();
             initHandles();
-            hideInsertionPointCursorController();
         }
 
         private void initDrawables() {
@@ -4548,10 +4638,10 @@
             if (mEndHandle != null) mEndHandle.hide();
         }
 
-        public void enterDrag() {
+        public void enterDrag(int dragAcceleratorMode) {
             // Just need to init the handles / hide insertion cursor.
             show();
-            mDragAcceleratorActive = true;
+            mDragAcceleratorMode = dragAcceleratorMode;
             // Start location of selection.
             mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX,
                     mLastDownPositionY);
@@ -4563,6 +4653,7 @@
             // the user to continue dragging across the screen to select text; TextView will
             // scroll as necessary.
             mTextView.getParent().requestDisallowInterceptTouchEvent(true);
+            mTextView.cancelLongPress();
         }
 
         public void onTouchEvent(MotionEvent event) {
@@ -4570,6 +4661,7 @@
             // selection and tap can move cursor from this tap position.
             final float eventX = event.getX();
             final float eventY = event.getY();
+            final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                     if (extractedTextModeWillBeStarted()) {
@@ -4582,7 +4674,8 @@
 
                         // Double tap detection
                         if (mGestureStayedInTapRegion) {
-                            if (mDoubleTap) {
+                            if (mTapState == TAP_STATE_DOUBLE_TAP
+                                    || mTapState == TAP_STATE_TRIPLE_CLICK) {
                                 final float deltaX = eventX - mDownPositionX;
                                 final float deltaY = eventY - mDownPositionY;
                                 final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
@@ -4593,8 +4686,12 @@
                                 boolean stayedInArea =
                                         distanceSquared < doubleTapSlop * doubleTapSlop;
 
-                                if (stayedInArea && isPositionOnText(eventX, eventY)) {
-                                    selectCurrentWordAndStartDrag();
+                                if (stayedInArea && (isMouse || isPositionOnText(eventX, eventY))) {
+                                    if (mTapState == TAP_STATE_DOUBLE_TAP) {
+                                        selectCurrentWordAndStartDrag();
+                                    } else if (mTapState == TAP_STATE_TRIPLE_CLICK) {
+                                        selectCurrentParagraphAndStartDrag();
+                                    }
                                     mDiscardNextActionUp = true;
                                 }
                             }
@@ -4639,94 +4736,168 @@
                         }
                     }
 
+                    if (isMouse && !isDragAcceleratorActive()) {
+                        final int offset = mTextView.getOffsetForPosition(eventX, eventY);
+                        if (mStartOffset != offset) {
+                            // Start character based drag accelerator.
+                            if (mTextActionMode != null) {
+                                mTextActionMode.finish();
+                            }
+                            enterDrag(DRAG_ACCELERATOR_MODE_CHARACTER);
+                            mDiscardNextActionUp = true;
+                            mHaventMovedEnoughToStartDrag = false;
+                        }
+                    }
+
                     if (mStartHandle != null && mStartHandle.isShowing()) {
                         // Don't do the drag if the handles are showing already.
                         break;
                     }
 
-                    if (mStartOffset != -1 && mTextView.getLayout() != null) {
-                        if (!mHaventMovedEnoughToStartDrag) {
-
-                            float y = eventY;
-                            if (mSwitchedLines) {
-                                // Offset the finger by the same vertical offset as the handles.
-                                // This improves visibility of the content being selected by
-                                // shifting the finger below the content, this is applied once
-                                // the user has switched lines.
-                                final float fingerOffset = (mStartHandle != null)
-                                        ? mStartHandle.getIdealVerticalOffset()
-                                        : touchSlop;
-                                y = eventY - fingerOffset;
-                            }
-
-                            final int currLine = getCurrentLineAdjustedForSlop(
-                                    mTextView.getLayout(),
-                                    mLineSelectionIsOn, y);
-                            if (!mSwitchedLines && currLine != mLineSelectionIsOn) {
-                                // Break early here, we want to offset the finger position from
-                                // the selection highlight, once the user moved their finger
-                                // to a different line we should apply the offset and *not* switch
-                                // lines until recomputing the position with the finger offset.
-                                mSwitchedLines = true;
-                                break;
-                            }
-
-                            int startOffset;
-                            int offset = mTextView.getOffsetAtCoordinate(currLine, eventX);
-                            // Snap to word boundaries.
-                            if (mStartOffset < offset) {
-                                // Expanding with end handle.
-                                offset = getWordEnd(offset);
-                                startOffset = getWordStart(mStartOffset);
-                            } else {
-                                // Expanding with start handle.
-                                offset = getWordStart(offset);
-                                startOffset = getWordEnd(mStartOffset);
-                            }
-                            mLineSelectionIsOn = currLine;
-                            Selection.setSelection((Spannable) mTextView.getText(),
-                                    startOffset, offset);
-                        }
-                    }
+                    updateSelection(event);
                     break;
 
                 case MotionEvent.ACTION_UP:
-                    if (mDragAcceleratorActive) {
-                        // No longer dragging to select text, let the parent intercept events.
-                        mTextView.getParent().requestDisallowInterceptTouchEvent(false);
-
-                        show();
-                        int startOffset = mTextView.getSelectionStart();
-                        int endOffset = mTextView.getSelectionEnd();
-
-                        // Since we don't let drag handles pass once they're visible, we need to
-                        // make sure the start / end locations are correct because the user *can*
-                        // switch directions during the initial drag.
-                        if (endOffset < startOffset) {
-                            int tmp = endOffset;
-                            endOffset = startOffset;
-                            startOffset = tmp;
-
-                            // Also update the selection with the right offsets in this case.
-                            Selection.setSelection((Spannable) mTextView.getText(),
-                                    startOffset, endOffset);
-                        }
-
-                        // Need to do this to display the handles.
-                        mStartHandle.showAtLocation(startOffset);
-                        mEndHandle.showAtLocation(endOffset);
-
-                        // No longer the first dragging motion, reset.
-                        startSelectionActionMode();
-
-                        mDragAcceleratorActive = false;
-                        mStartOffset = -1;
-                        mSwitchedLines = false;
+                    if (!isDragAcceleratorActive()) {
+                        break;
                     }
+                    updateSelection(event);
+
+                    // No longer dragging to select text, let the parent intercept events.
+                    mTextView.getParent().requestDisallowInterceptTouchEvent(false);
+
+                    int startOffset = mTextView.getSelectionStart();
+                    int endOffset = mTextView.getSelectionEnd();
+
+                    // Since we don't let drag handles pass once they're visible, we need to
+                    // make sure the start / end locations are correct because the user *can*
+                    // switch directions during the initial drag.
+                    if (endOffset < startOffset) {
+                        int tmp = endOffset;
+                        endOffset = startOffset;
+                        startOffset = tmp;
+
+                        // Also update the selection with the right offsets in this case.
+                        Selection.setSelection((Spannable) mTextView.getText(),
+                                startOffset, endOffset);
+                    }
+                    if (startOffset != endOffset) {
+                        startSelectionActionMode();
+                    }
+
+                    // No longer the first dragging motion, reset.
+                    resetDragAcceleratorState();
                     break;
             }
         }
 
+        private void updateSelection(MotionEvent event) {
+            if (mTextView.getLayout() != null) {
+                switch (mDragAcceleratorMode) {
+                    case DRAG_ACCELERATOR_MODE_CHARACTER:
+                        updateCharacterBasedSelection(event);
+                        break;
+                    case DRAG_ACCELERATOR_MODE_WORD:
+                        updateWordBasedSelection(event);
+                        break;
+                    case DRAG_ACCELERATOR_MODE_PARAGRAPH:
+                        updateParagraphBasedSelection(event);
+                        break;
+                }
+            }
+        }
+
+        /**
+         * If the TextView allows text selection, selects the current paragraph and starts a drag.
+         *
+         * @return true if the drag was started.
+         */
+        private boolean selectCurrentParagraphAndStartDrag() {
+            if (mInsertionActionModeRunnable != null) {
+                mTextView.removeCallbacks(mInsertionActionModeRunnable);
+            }
+            if (mTextActionMode != null) {
+                mTextActionMode.finish();
+            }
+            if (!selectCurrentParagraph()) {
+                return false;
+            }
+            enterDrag(SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_PARAGRAPH);
+            return true;
+        }
+
+        private void updateCharacterBasedSelection(MotionEvent event) {
+            final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
+            Selection.setSelection((Spannable) mTextView.getText(), mStartOffset, offset);
+        }
+
+        private void updateWordBasedSelection(MotionEvent event) {
+            if (mHaventMovedEnoughToStartDrag) {
+                return;
+            }
+            final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
+            final ViewConfiguration viewConfig = ViewConfiguration.get(
+                    mTextView.getContext());
+            final float eventX = event.getX();
+            final float eventY = event.getY();
+            final int currLine;
+            if (isMouse) {
+                // No need to offset the y coordinate for mouse input.
+                currLine = mTextView.getLineAtCoordinate(eventY);
+            } else {
+                float y = eventY;
+                if (mSwitchedLines) {
+                    // Offset the finger by the same vertical offset as the handles.
+                    // This improves visibility of the content being selected by
+                    // shifting the finger below the content, this is applied once
+                    // the user has switched lines.
+                    final int touchSlop = viewConfig.getScaledTouchSlop();
+                    final float fingerOffset = (mStartHandle != null)
+                            ? mStartHandle.getIdealVerticalOffset()
+                            : touchSlop;
+                    y = eventY - fingerOffset;
+                }
+
+                currLine = getCurrentLineAdjustedForSlop(mTextView.getLayout(), mLineSelectionIsOn,
+                        y);
+                if (!mSwitchedLines && currLine != mLineSelectionIsOn) {
+                    // Break early here, we want to offset the finger position from
+                    // the selection highlight, once the user moved their finger
+                    // to a different line we should apply the offset and *not* switch
+                    // lines until recomputing the position with the finger offset.
+                    mSwitchedLines = true;
+                    return;
+                }
+            }
+
+            int startOffset;
+            int offset = mTextView.getOffsetAtCoordinate(currLine, eventX);
+            // Snap to word boundaries.
+            if (mStartOffset < offset) {
+                // Expanding with end handle.
+                offset = getWordEnd(offset);
+                startOffset = getWordStart(mStartOffset);
+            } else {
+                // Expanding with start handle.
+                offset = getWordStart(offset);
+                startOffset = getWordEnd(mStartOffset);
+            }
+            mLineSelectionIsOn = currLine;
+            Selection.setSelection((Spannable) mTextView.getText(),
+                    startOffset, offset);
+        }
+
+        private void updateParagraphBasedSelection(MotionEvent event) {
+            final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
+
+            final int start = Math.min(offset, mStartOffset);
+            final int end = Math.max(offset, mStartOffset);
+            final long paragraphsRange = getParagraphsRange(start, end);
+            final int selectionStart = TextUtils.unpackRangeStartFromLong(paragraphsRange);
+            final int selectionEnd = TextUtils.unpackRangeEndFromLong(paragraphsRange);
+            Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
+        }
+
         /**
          * @param event
          */
@@ -4749,8 +4920,12 @@
 
         public void resetTouchOffsets() {
             mMinTouchOffset = mMaxTouchOffset = -1;
+            resetDragAcceleratorState();
+        }
+
+        private void resetDragAcceleratorState() {
             mStartOffset = -1;
-            mDragAcceleratorActive = false;
+            mDragAcceleratorMode = DRAG_ACCELERATOR_MODE_INACTIVE;
             mSwitchedLines = false;
         }
 
@@ -4765,7 +4940,7 @@
          * @return true if the user is selecting text using the drag accelerator.
          */
         public boolean isDragAcceleratorActive() {
-            return mDragAcceleratorActive;
+            return mDragAcceleratorMode != DRAG_ACCELERATOR_MODE_INACTIVE;
         }
 
         public void onTouchModeChanged(boolean isInTouchMode) {
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 607e955..ee73092 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1643,8 +1643,16 @@
 
         boolean handled = false;
         int action = event.getAction();
+        if (KeyEvent.isConfirmKey(keyCode)
+                && event.hasNoModifiers() && action == KeyEvent.ACTION_UP) {
+            handled = resurrectSelectionIfNeeded();
+            if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
+                keyPressed();
+                handled = true;
+            }
+        }
 
-        if (action != KeyEvent.ACTION_UP) {
+        if (!handled && action != KeyEvent.ACTION_UP) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_DPAD_LEFT:
                     if (event.hasNoModifiers()) {
@@ -1674,28 +1682,6 @@
                     }
                     break;
 
-                case KeyEvent.KEYCODE_DPAD_CENTER:
-                case KeyEvent.KEYCODE_ENTER:
-                    if (event.hasNoModifiers()) {
-                        handled = resurrectSelectionIfNeeded();
-                        if (!handled
-                                && event.getRepeatCount() == 0 && getChildCount() > 0) {
-                            keyPressed();
-                            handled = true;
-                        }
-                    }
-                    break;
-
-                case KeyEvent.KEYCODE_SPACE:
-                    if (mPopup == null || !mPopup.isShowing()) {
-                        if (event.hasNoModifiers()) {
-                            handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_DOWN);
-                        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                            handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
-                        }
-                    }
-                    break;
-
                 case KeyEvent.KEYCODE_PAGE_UP:
                     if (event.hasNoModifiers()) {
                         handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 53ca6d1..064808b 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2180,8 +2180,17 @@
 
         boolean handled = false;
         int action = event.getAction();
+        if (KeyEvent.isConfirmKey(keyCode)
+                && event.hasNoModifiers() && action == KeyEvent.ACTION_UP) {
+            handled = resurrectSelectionIfNeeded();
+            if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
+                keyPressed();
+                handled = true;
+            }
+        }
 
-        if (action != KeyEvent.ACTION_UP) {
+
+        if (!handled && action != KeyEvent.ACTION_UP) {
             switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_UP:
                 if (event.hasNoModifiers()) {
@@ -2229,29 +2238,6 @@
                 }
                 break;
 
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_ENTER:
-                if (event.hasNoModifiers()) {
-                    handled = resurrectSelectionIfNeeded();
-                    if (!handled
-                            && event.getRepeatCount() == 0 && getChildCount() > 0) {
-                        keyPressed();
-                        handled = true;
-                    }
-                }
-                break;
-
-            case KeyEvent.KEYCODE_SPACE:
-                if (mPopup == null || !mPopup.isShowing()) {
-                    if (event.hasNoModifiers()) {
-                        handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_DOWN);
-                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                        handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
-                    }
-                    handled = true;
-                }
-                break;
-
             case KeyEvent.KEYCODE_PAGE_UP:
                 if (event.hasNoModifiers()) {
                     handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 7b9de79..f4c343a 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+
 import com.android.internal.R;
 
 import android.annotation.NonNull;
@@ -1311,6 +1313,8 @@
             p.width = mLastWidth = mWidth;
         }
 
+        p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+
         // Used for debugging.
         p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 94b75b7..17c803f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,7 +17,6 @@
 package android.widget;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-
 import android.R;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
@@ -115,6 +114,7 @@
 import android.view.DragEvent;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
+import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -618,9 +618,6 @@
     private final Paint mHighlightPaint;
     private boolean mHighlightPathBogus = true;
 
-    private boolean mFirstTouch = false;
-    private long mLastTouchUpTime = 0;
-
     // Although these fields are specific to editable text, they are not added to Editor because
     // they are defined by the TextView's style and are theme-dependent.
     int mCursorDrawableRes;
@@ -5958,15 +5955,12 @@
         return mLayout != null ? mLayout.getHeight() : 0;
     }
 
-    /**
-     * @hide
-     */
     @Override
-    public int getPointerShape(MotionEvent event, float x, float y) {
+    public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
         if (isTextSelectable() || isTextEditable()) {
-            return PointerIcon.STYLE_TEXT;
+            return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_TEXT);
         }
-        return super.getPointerShape(event, x, y);
+        return super.getPointerIcon(event, x, y);
     }
 
     @Override
@@ -8406,23 +8400,6 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
-
-        if (mEditor != null && action == MotionEvent.ACTION_DOWN) {
-            // Detect double tap and inform the Editor.
-            if (mFirstTouch && (SystemClock.uptimeMillis() - mLastTouchUpTime) <=
-                    ViewConfiguration.getDoubleTapTimeout()) {
-                mEditor.mDoubleTap = true;
-                mFirstTouch = false;
-            } else {
-                mEditor.mDoubleTap = false;
-                mFirstTouch = true;
-            }
-        }
-
-        if (action == MotionEvent.ACTION_UP) {
-            mLastTouchUpTime = SystemClock.uptimeMillis();
-        }
-
         if (mEditor != null) {
             mEditor.onTouchEvent(event);
 
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 61ee00c..66374a6 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -359,6 +359,7 @@
 
         if (mIconView != null) {
             if (resId != 0) {
+                mIconView.setVisibility(View.VISIBLE);
                 mIconView.setImageResource(mIconId);
             } else {
                 mIconView.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index e607a3f..85cc841 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -175,7 +175,7 @@
         }
 
         private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
-                new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
+                new TreeMap<>(
                         new Comparator<InputMethodInfo>() {
                             @Override
                             public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
@@ -192,14 +192,9 @@
                             }
                         });
 
-        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
-            return getSortedInputMethodAndSubtypeList(true, false, false);
-        }
-
         public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(
-                boolean showSubtypes, boolean includeAuxiliarySubtypes, boolean isScreenLocked) {
-            final ArrayList<ImeSubtypeListItem> imList =
-                    new ArrayList<ImeSubtypeListItem>();
+                boolean includeAuxiliarySubtypes, boolean isScreenLocked) {
+            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<>();
             final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
                     mSettings.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked(
                             mContext);
@@ -219,12 +214,12 @@
                     continue;
                 }
                 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
-                HashSet<String> enabledSubtypeSet = new HashSet<String>();
+                HashSet<String> enabledSubtypeSet = new HashSet<>();
                 for (InputMethodSubtype subtype : explicitlyOrImplicitlyEnabledSubtypeList) {
                     enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
                 }
                 final CharSequence imeLabel = imi.loadLabel(mPm);
-                if (showSubtypes && enabledSubtypeSet.size() > 0) {
+                if (enabledSubtypeSet.size() > 0) {
                     final int subtypeCount = imi.getSubtypeCount();
                     if (DEBUG) {
                         Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
@@ -532,7 +527,8 @@
     public void resetCircularListLocked(Context context) {
         mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
         mController = ControllerImpl.createFrom(mController,
-                mSubtypeList.getSortedInputMethodAndSubtypeList());
+                mSubtypeList.getSortedInputMethodAndSubtypeList(
+                        false /* includeAuxiliarySubtypes */, false /* isScreenLocked */));
     }
 
     public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi,
@@ -546,10 +542,10 @@
         return mController.getNextInputMethod(onlyCurrentIme, imi, subtype);
     }
 
-    public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeListLocked(boolean showSubtypes,
+    public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeListLocked(
             boolean includingAuxiliarySubtypes, boolean isScreenLocked) {
         return mSubtypeList.getSortedInputMethodAndSubtypeList(
-                showSubtypes, includingAuxiliarySubtypes, isScreenLocked);
+                includingAuxiliarySubtypes, isScreenLocked);
     }
 
     public void dump(final Printer pw) {
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index cc677cc..e276bc6 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -36,6 +36,24 @@
     public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
     public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
 
+    /**
+     * Logged when the user docks a window from recents by longpressing a task and dragging it to
+     * the dock area.
+     */
+    public static final int ACTION_WINDOW_DOCK_DRAG_DROP = 265;
+
+    /**
+     * Logged when the user docks a fullscreen window by long pressing recents which also opens
+     * recents on the lower/right side.
+     */
+    public static final int ACTION_WINDOW_DOCK_LONGPRESS = 266;
+
+    /**
+     * Logged when the user docks a window by dragging from the navbar which also opens recents on
+     * the lower/right side.
+     */
+    public static final int ACTION_WINDOW_DOCK_SWIPE = 267;
+
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
             throw new IllegalArgumentException("Must define metric category");
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4a969b2..cc815c4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -7732,26 +7732,35 @@
                 }
 
                 final Uid u = getUidStatsLocked(mapUid(entry.uid));
-                u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
-                        entry.rxPackets);
-                u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
-                        entry.txPackets);
-                rxPackets.put(u.getUid(), entry.rxPackets);
-                txPackets.put(u.getUid(), entry.txPackets);
+                if (entry.rxBytes != 0) {
+                    u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
+                            entry.rxPackets);
+                    mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+                            entry.rxBytes);
+                    mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+                            entry.rxPackets);
 
-                // Sum the total number of packets so that the Rx Power and Tx Power can
-                // be evenly distributed amongst the apps.
-                totalRxPackets += entry.rxPackets;
-                totalTxPackets += entry.txPackets;
+                    rxPackets.put(u.getUid(), entry.rxPackets);
 
-                mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
-                        entry.rxBytes);
-                mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
-                        entry.txBytes);
-                mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
-                        entry.rxPackets);
-                mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
-                        entry.txPackets);
+                    // Sum the total number of packets so that the Rx Power can
+                    // be evenly distributed amongst the apps.
+                    totalRxPackets += entry.rxPackets;
+                }
+
+                if (entry.txBytes != 0) {
+                    u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
+                            entry.txPackets);
+                    mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+                            entry.txBytes);
+                    mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+                            entry.txPackets);
+
+                    txPackets.put(u.getUid(), entry.txPackets);
+
+                    // Sum the total number of packets so that the Tx Power can
+                    // be evenly distributed amongst the apps.
+                    totalTxPackets += entry.txPackets;
+                }
             }
         }
 
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 8186378..d23f26d 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -145,8 +145,9 @@
     native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
 
-    private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
-        VM_HOOKS.postForkChild(debugFlags, instructionSet);
+    private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
+            String instructionSet) {
+        VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
     }
 
 
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 75ca639..1b44ff3 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -63,17 +63,18 @@
     private boolean mReportNextDraw;
 
     private Drawable mCaptionBackgroundDrawable;
+    private Drawable mUserCaptionBackgroundDrawable;
     private Drawable mResizingBackgroundDrawable;
     private ColorDrawable mStatusBarColor;
 
     public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
             Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
-            int statusBarColor) {
+            Drawable userCaptionBackgroundDrawable, int statusBarColor) {
         setName("ResizeFrame");
 
         mRenderer = renderer;
         onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable,
-                statusBarColor);
+                userCaptionBackgroundDrawable, statusBarColor);
 
         // Create a render node for the content and frame backdrop
         // which can be resized independently from the content.
@@ -92,10 +93,12 @@
     }
 
     void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable,
-            Drawable captionBackgroundDrawableDrawable, int statusBarColor) {
+            Drawable captionBackgroundDrawableDrawable, Drawable userCaptionBackgroundDrawable,
+            int statusBarColor) {
         mDecorView = decorView;
         mResizingBackgroundDrawable = resizingBackgroundDrawable;
         mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable;
+        mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
         if (statusBarColor != 0) {
             mStatusBarColor = new ColorDrawable(statusBarColor);
             addSystemBarNodeIfNeeded();
@@ -281,8 +284,10 @@
 
         // Draw the caption and content backdrops in to our render node.
         DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height);
-        mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
-        mCaptionBackgroundDrawable.draw(canvas);
+        final Drawable drawable = mUserCaptionBackgroundDrawable != null
+                ? mUserCaptionBackgroundDrawable : mCaptionBackgroundDrawable;
+        drawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
+        drawable.draw(canvas);
 
         // The backdrop: clear everything with the background. Clipping is done elsewhere.
         mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height);
@@ -324,4 +329,8 @@
             mChoreographer.postFrameCallback(this);
         }
     }
+
+    void setUserCaptionBackgroundDrawable(Drawable userCaptionBackgroundDrawable) {
+        mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
+    }
 }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 531ba2f..6a1e07b 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -17,11 +17,13 @@
 package com.android.internal.policy;
 
 import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
 import com.android.internal.view.FloatingActionMode;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
 import com.android.internal.view.menu.MenuHelper;
+import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorCaptionView;
@@ -67,6 +69,7 @@
 import android.widget.FrameLayout;
 import android.widget.PopupWindow;
 
+import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.view.View.MeasureSpec.AT_MOST;
@@ -74,6 +77,8 @@
 import static android.view.View.MeasureSpec.getMode;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
+import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
@@ -184,9 +189,10 @@
 
     private boolean mWindowResizeCallbacksAdded = false;
 
-    BackdropFrameRenderer mBackdropFrameRenderer = null;
+    private BackdropFrameRenderer mBackdropFrameRenderer = null;
     private Drawable mResizingBackgroundDrawable;
     private Drawable mCaptionBackgroundDrawable;
+    private Drawable mUserCaptionBackgroundDrawable;
 
     DecorView(Context context, int featureId, PhoneWindow window) {
         super(context);
@@ -681,9 +687,10 @@
         }
 
         // Reuse the context menu builder.
+        final PhoneWindowMenuCallback callback = mWindow.mContextMenuCallback;
         if (mWindow.mContextMenu == null) {
             mWindow.mContextMenu = new ContextMenuBuilder(getContext());
-            mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
+            mWindow.mContextMenu.setCallback(callback);
         } else {
             mWindow.mContextMenu.clearAll();
         }
@@ -695,9 +702,11 @@
             helper = mWindow.mContextMenu.showDialog(originalView, originalView.getWindowToken());
         }
 
-        if (helper != null) {
-            helper.setPresenterCallback(mWindow.mContextMenuCallback);
-        }
+        // If it's a dialog, the callback needs to handle showing sub-menus.
+        // Either way, the callback is required for propagating selection to
+        // Context.onContextMenuItemSelected().
+        callback.setShowDialogForSubmenu(!isPopup);
+        helper.setPresenterCallback(callback);
 
         mWindow.mContextMenuHelper = helper;
         return helper != null;
@@ -1185,7 +1194,7 @@
         invalidate();
 
         int opacity = PixelFormat.OPAQUE;
-        if (ActivityManager.StackId.hasWindowShadow(mStackId)) {
+        if (StackId.hasWindowShadow(mStackId)) {
             // If the window has a shadow, it must be translucent.
             opacity = PixelFormat.TRANSLUCENT;
         } else{
@@ -1568,30 +1577,44 @@
 
     void onConfigurationChanged() {
         int workspaceId = getStackId();
-        if (mDecorCaptionView != null) {
-            if (mStackId != workspaceId) {
-                mStackId = workspaceId;
+        if (mStackId != workspaceId) {
+            mStackId = workspaceId;
+            if (mDecorCaptionView == null && StackId.hasWindowDecor(mStackId)) {
+                // Configuration now requires a caption.
+                final LayoutInflater inflater = mWindow.getLayoutInflater();
+                mDecorCaptionView = createDecorCaptionView(inflater);
+                if (mDecorCaptionView != null) {
+                    if (mDecorCaptionView.getParent() == null) {
+                        addView(mDecorCaptionView, 0,
+                                new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+                    }
+                    removeView(mContentRoot);
+                    mDecorCaptionView.addView(mContentRoot,
+                            new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
+                }
+            } else if (mDecorCaptionView != null) {
                 // We might have to change the kind of surface before we do anything else.
-                mDecorCaptionView.onConfigurationChanged(
-                        ActivityManager.StackId.hasWindowDecor(mStackId));
-                enableCaption(ActivityManager.StackId.hasWindowDecor(workspaceId));
+                mDecorCaptionView.onConfigurationChanged(StackId.hasWindowDecor(mStackId));
+                enableCaption(StackId.hasWindowDecor(workspaceId));
             }
         }
         initializeElevation();
     }
 
-    View onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
+    void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
         mStackId = getStackId();
 
         mResizingBackgroundDrawable = getResizingBackgroundDrawable(
                 mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
-        mCaptionBackgroundDrawable =
-                getContext().getDrawable(R.drawable.decor_caption_title_focused);
+        if (mCaptionBackgroundDrawable == null) {
+            mCaptionBackgroundDrawable = getContext().getDrawable(
+                    R.drawable.decor_caption_title_focused);
+        }
 
         if (mBackdropFrameRenderer != null) {
             mBackdropFrameRenderer.onResourcesLoaded(
                     this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
-                    getCurrentColor(mStatusColorViewState));
+                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
         }
 
         mDecorCaptionView = createDecorCaptionView(inflater);
@@ -1608,17 +1631,16 @@
         }
         mContentRoot = (ViewGroup) root;
         initializeElevation();
-        return root;
     }
 
     // Free floating overlapping windows require a caption.
     private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {
-        DecorCaptionView DecorCaptionView = null;
-        for (int i = getChildCount() - 1; i >= 0 && DecorCaptionView == null; i--) {
+        DecorCaptionView decorCaptionView = null;
+        for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {
             View view = getChildAt(i);
             if (view instanceof DecorCaptionView) {
                 // The decor was most likely saved from a relaunch - so reuse it.
-                DecorCaptionView = (DecorCaptionView) view;
+                decorCaptionView = (DecorCaptionView) view;
                 removeViewAt(i);
             }
         }
@@ -1626,31 +1648,75 @@
         final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
                 attrs.type == TYPE_APPLICATION;
         // Only a non floating application window on one of the allowed workspaces can get a caption
-        if (!mWindow.isFloating() && isApplication
-                && ActivityManager.StackId.hasWindowDecor(mStackId)) {
+        if (!mWindow.isFloating() && isApplication && StackId.hasWindowDecor(mStackId)) {
             // Dependent on the brightness of the used title we either use the
             // dark or the light button frame.
-            if (DecorCaptionView == null) {
-                Context context = getContext();
-                TypedValue value = new TypedValue();
-                context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
-                inflater = inflater.from(context);
-                if (Color.luminance(value.data) < 0.5) {
-                    DecorCaptionView = (DecorCaptionView) inflater.inflate(
-                            R.layout.decor_caption_dark, null);
-                } else {
-                    DecorCaptionView = (DecorCaptionView) inflater.inflate(
-                            R.layout.decor_caption_light, null);
-                }
+            if (decorCaptionView == null) {
+                decorCaptionView = inflateDecorCaptionView(inflater);
             }
-            DecorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
+            decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
         } else {
-            DecorCaptionView = null;
+            decorCaptionView = null;
         }
 
         // Tell the decor if it has a visible caption.
-        enableCaption(DecorCaptionView != null);
-        return DecorCaptionView;
+        enableCaption(decorCaptionView != null);
+        return decorCaptionView;
+    }
+
+    private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {
+        final Context context = getContext();
+        // We make a copy of the inflater, so it has the right context associated with it.
+        inflater = inflater.from(context);
+        final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption,
+                null);
+        setDecorCaptionShade(context, view);
+        return view;
+    }
+
+    private void setDecorCaptionShade(Context context, DecorCaptionView view) {
+        final int shade = mWindow.getDecorCaptionShade();
+        switch (shade) {
+            case DECOR_CAPTION_SHADE_LIGHT:
+                setLightDecorCaptionShade(view);
+                break;
+            case DECOR_CAPTION_SHADE_DARK:
+                setDarkDecorCaptionShade(view);
+                break;
+            default: {
+                TypedValue value = new TypedValue();
+                context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+                // We invert the shade depending on brightness of the theme. Dark shade for light
+                // theme and vice versa. Thanks to this the buttons should be visible on the
+                // background.
+                if (Color.luminance(value.data) < 0.5) {
+                    setLightDecorCaptionShade(view);
+                } else {
+                    setDarkDecorCaptionShade(view);
+                }
+                break;
+            }
+        }
+    }
+
+    void updateDecorCaptionShade() {
+        if (mDecorCaptionView != null) {
+            setDecorCaptionShade(getContext(), mDecorCaptionView);
+        }
+    }
+
+    private void setLightDecorCaptionShade(DecorCaptionView view) {
+        view.findViewById(R.id.maximize_window).setBackgroundResource(
+                R.drawable.decor_maximize_button_light);
+        view.findViewById(R.id.close_window).setBackgroundResource(
+                R.drawable.decor_close_button_light);
+    }
+
+    private void setDarkDecorCaptionShade(DecorCaptionView view) {
+        view.findViewById(R.id.maximize_window).setBackgroundResource(
+                R.drawable.decor_maximize_button_dark);
+        view.findViewById(R.id.close_window).setBackgroundResource(
+                R.drawable.decor_close_button_dark);
     }
 
     /**
@@ -1735,11 +1801,11 @@
         if (mBackdropFrameRenderer != null) {
             return;
         }
-        final ThreadedRenderer renderer = (ThreadedRenderer) getHardwareRenderer();
+        final ThreadedRenderer renderer = getHardwareRenderer();
         if (renderer != null) {
             mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
                     initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
-                    getCurrentColor(mStatusColorViewState));
+                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
 
             // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
             // If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -1805,7 +1871,7 @@
         final boolean wasAdjustedForStack = mElevationAdjustedForStack;
         // Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null)
         // since the shadow is bound to the content size and not the target size.
-        if (ActivityManager.StackId.hasWindowShadow(mStackId) && !isResizing()) {
+        if (StackId.hasWindowShadow(mStackId) && !isResizing()) {
             elevation = hasWindowFocus() ?
                     DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
             // TODO(skuhne): Remove this if clause once b/22668382 got fixed.
@@ -1849,6 +1915,16 @@
                 getResources().getDisplayMetrics());
     }
 
+    /**
+     * Provide an override of the caption background drawable.
+     */
+    void setUserCaptionBackgroundDrawable(Drawable drawable) {
+        mUserCaptionBackgroundDrawable = drawable;
+        if (mBackdropFrameRenderer != null) {
+            mBackdropFrameRenderer.setUserCaptionBackgroundDrawable(drawable);
+        }
+    }
+
     private static class ColorViewState {
         View view = null;
         int targetVisibility = View.INVISIBLE;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 337bb69..2d8bfd4 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -94,7 +94,6 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
@@ -128,7 +127,7 @@
      * Simple callback used by the context menu and its submenus. The options
      * menu submenus do not use this (their behavior is more complex).
      */
-    final DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU);
+    final PhoneWindowMenuCallback mContextMenuCallback = new PhoneWindowMenuCallback(this);
 
     final TypedValue mMinWidthMajor = new TypedValue();
     final TypedValue mMinWidthMinor = new TypedValue();
@@ -273,6 +272,8 @@
     private boolean mIsStartingWindow;
     private int mTheme = -1;
 
+    private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
+
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService("window"));
@@ -661,6 +662,13 @@
         }
     }
 
+    @Override
+    public void onMultiWindowModeChanged() {
+        if (mDecor != null) {
+            mDecor.onConfigurationChanged();
+        }
+    }
+
     private static void clearMenuViews(PanelFeatureState st) {
         // This can be called on config changes, so we should make sure
         // the views will be reconstructed based on the new orientation, etc.
@@ -2527,7 +2535,7 @@
         }
 
         mDecor.startChanging();
-        final View in = mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
+        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
 
         ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
         if (contentParent == null) {
@@ -3591,27 +3599,34 @@
      * <li> Calls back to the callback's onMenuItemSelected when an item is
      * selected.
      */
-    private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
-        private int mFeatureId;
+    public static final class PhoneWindowMenuCallback
+            implements MenuBuilder.Callback, MenuPresenter.Callback {
+        private static final int FEATURE_ID = FEATURE_CONTEXT_MENU;
+
+        private final PhoneWindow mWindow;
+
         private MenuDialogHelper mSubMenuHelper;
 
-        public DialogMenuCallback(int featureId) {
-            mFeatureId = featureId;
+        private boolean mShowDialogForSubmenu;
+
+        public PhoneWindowMenuCallback(PhoneWindow window) {
+            mWindow = window;
         }
 
+        @Override
         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
             if (menu.getRootMenu() != menu) {
                 onCloseSubMenu(menu);
             }
 
             if (allMenusAreClosing) {
-                Callback callback = getCallback();
-                if (callback != null && !isDestroyed()) {
-                    callback.onPanelClosed(mFeatureId, menu);
+                final Callback callback = mWindow.getCallback();
+                if (callback != null && !mWindow.isDestroyed()) {
+                    callback.onPanelClosed(FEATURE_ID, menu);
                 }
 
-                if (menu == mContextMenu) {
-                    dismissContextMenu();
+                if (menu == mWindow.mContextMenu) {
+                    mWindow.dismissContextMenu();
                 }
 
                 // Dismiss the submenu, if it is showing
@@ -3622,33 +3637,45 @@
             }
         }
 
-        public void onCloseSubMenu(MenuBuilder menu) {
-            Callback callback = getCallback();
-            if (callback != null && !isDestroyed()) {
-                callback.onPanelClosed(mFeatureId, menu.getRootMenu());
+        private void onCloseSubMenu(MenuBuilder menu) {
+            final Callback callback = mWindow.getCallback();
+            if (callback != null && !mWindow.isDestroyed()) {
+                callback.onPanelClosed(FEATURE_ID, menu.getRootMenu());
             }
         }
 
+        @Override
         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
-            Callback callback = getCallback();
-            return (callback != null && !isDestroyed())
-                    && callback.onMenuItemSelected(mFeatureId, item);
+            final Callback callback = mWindow.getCallback();
+            return callback != null && !mWindow.isDestroyed()
+                    && callback.onMenuItemSelected(FEATURE_ID, item);
         }
 
+        @Override
         public void onMenuModeChange(MenuBuilder menu) {
         }
 
+        @Override
         public boolean onOpenSubMenu(MenuBuilder subMenu) {
-            if (subMenu == null) return false;
+            if (subMenu == null) {
+                return false;
+            }
 
             // Set a simple callback for the submenu
             subMenu.setCallback(this);
 
-            // The window manager will give us a valid window token
-            mSubMenuHelper = new MenuDialogHelper(subMenu);
-            mSubMenuHelper.show(null);
+            if (mShowDialogForSubmenu) {
+                // The window manager will give us a valid window token
+                mSubMenuHelper = new MenuDialogHelper(subMenu);
+                mSubMenuHelper.show(null);
+                return true;
+            }
 
-            return true;
+            return false;
+        }
+
+        public void setShowDialogForSubmenu(boolean enabled) {
+            mShowDialogForSubmenu = enabled;
         }
     }
 
@@ -3720,4 +3747,21 @@
             }
         }
     }
+
+    @Override
+    public void setResizingCaptionDrawable(Drawable drawable) {
+        mDecor.setUserCaptionBackgroundDrawable(drawable);
+    }
+
+    @Override
+    public void setDecorCaptionShade(int decorCaptionShade) {
+        mDecorCaptionShade = decorCaptionShade;
+        if (mDecor != null) {
+            mDecor.updateDecorCaptionShade();
+        }
+    }
+
+    int getDecorCaptionShade() {
+        return mDecorCaptionShade;
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 11ef18b..849d314 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -28,7 +28,7 @@
     void removeIcon(int index);
     void disable(int state1, int state2);
     void animateExpandNotificationsPanel();
-    void animateExpandSettingsPanel();
+    void animateExpandSettingsPanel(String subPanel);
     void animateCollapsePanels();
     void setSystemUiVisibility(int vis, int mask);
     void topAppWindowChanged(boolean menuVisible);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 6c957be..0a4ad06 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -39,7 +39,7 @@
     void topAppWindowChanged(boolean menuVisible);
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
-    void expandSettingsPanel();
+    void expandSettingsPanel(String subPanel);
     void setCurrentUser(int newUserId);
 
     // ---- Methods below are for use by the status bar policy services ----
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 554d367..406b487 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -779,6 +779,10 @@
         @Override
         public final void handleMessage(Message msg) {
             if (!mHasQuit) {
+                if (mSm != null) {
+                    mSm.onPreHandleMessage(msg);
+                }
+
                 if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
 
                 /** Save the current message */
@@ -802,6 +806,10 @@
 
                 // We need to check if mSm == null here as we could be quitting.
                 if (mDbg && mSm != null) mSm.log("handleMessage: X");
+
+                if (mSm != null) {
+                    mSm.onPostHandleMessage(msg);
+                }
             }
         }
 
@@ -1274,6 +1282,21 @@
     }
 
     /**
+     * Notifies subclass that the StateMachine handler is about to process the Message msg
+     * @param msg The message that is being handled
+     */
+    protected void onPreHandleMessage(Message msg) {
+    }
+
+    /**
+     * Notifies subclass that the StateMachine handler has finished processing the Message msg and
+     * has possibly transitioned to a new state.
+     * @param msg The message that is being handled
+     */
+    protected void onPostHandleMessage(Message msg) {
+    }
+
+    /**
      * Add a new state to the state machine
      * @param state the state to add
      * @param parent the parent of state
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 6a5f6d8..c2adc42 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -242,13 +242,13 @@
     @Override
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
         if (subMenu.hasVisibleItems()) {
-            MenuPopupHelper subPopup = new MenuPopupHelper(
-                    mContext, subMenu, mShownAnchorView, mOverflowOnly, mPopupStyleAttr,
-                    mPopupStyleRes);
+            final MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu,
+                    mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
             subPopup.setPresenterCallback(mPresenterCallback);
             subPopup.setForceShowIcon(mAdapter.getForceShowIcon());
 
-            if (subPopup.tryShow()) {
+            // Show the new sub-menu popup at the same location as this popup.
+            if (subPopup.tryShow(mXOffset, mYOffset)) {
                 if (mPresenterCallback != null) {
                     mPresenterCallback.onOpenSubMenu(subMenu);
                 }
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index d747686..c3fe9e7 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -319,6 +319,10 @@
                         captionHeight + mContent.getMeasuredHeight());
             }
         }
+
+        // This assumes that the caption bar is at the top.
+        mOwner.notifyRestrictedCaptionAreaCallback(mMaximize.getLeft(), mMaximize.getTop(),
+                mClose.getRight(), mClose.getBottom());
     }
     /**
      * Determine if the workspace is entirely covered by the window.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 6c223c3..e38d82f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -64,6 +64,11 @@
     private static final boolean DEBUG = false;
 
     /**
+     * The key to identify when the lock pattern enabled flag is being acccessed for legacy reasons.
+     */
+    public static final String LEGACY_LOCK_PATTERN_ENABLED = "legacy_lock_pattern_enabled";
+
+    /**
      * The number of incorrect attempts before which we fall back on an alternative
      * method of verifying the user, and resetting their lock pattern.
      */
@@ -1014,6 +1019,19 @@
         return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
     }
 
+    @Deprecated
+    public boolean isLegacyLockPatternEnabled(int userId) {
+        // Note: this value should default to {@code true} to avoid any reset that might result.
+        // We must use a special key to read this value, since it will by default return the value
+        // based on the new logic.
+        return getBoolean(LEGACY_LOCK_PATTERN_ENABLED, true, userId);
+    }
+
+    @Deprecated
+    public void setLegacyLockPatternEnabled(int userId) {
+        setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
+    }
+
     private boolean isLockPatternEnabled(int mode, int userId) {
         return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
                 && savedPatternExists(userId);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f1e7afb..bdbd096 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -250,7 +250,8 @@
     libminikin \
     libprocessgroup \
     libnativebridge \
-    libradio_metadata
+    libradio_metadata \
+    libnativeloader
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index dac6d96..ab0df55 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -56,10 +56,11 @@
     return result;
 }
 
-static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path) {
+static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path,
+        jint ttcIndex) {
     NPE_CHECK_RETURN_ZERO(env, path);
     ScopedUtfChars str(env, path);
-    SkTypeface* face = SkTypeface::CreateFromFile(str.c_str());
+    SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
     if (face == NULL) {
         ALOGE("addFont failed to create font %s", str.c_str());
         return false;
@@ -69,10 +70,10 @@
 }
 
 static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
-        jstring path, jint weight, jboolean isItalic) {
+        jstring path, jint ttcIndex, jint weight, jboolean isItalic) {
     NPE_CHECK_RETURN_ZERO(env, path);
     ScopedUtfChars str(env, path);
-    SkTypeface* face = SkTypeface::CreateFromFile(str.c_str());
+    SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
     if (face == NULL) {
         ALOGE("addFont failed to create font %s", str.c_str());
         return false;
@@ -127,8 +128,8 @@
 static const JNINativeMethod gFontFamilyMethods[] = {
     { "nCreateFamily",         "(Ljava/lang/String;I)J", (void*)FontFamily_create },
     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
-    { "nAddFont",              "(JLjava/lang/String;)Z", (void*)FontFamily_addFont },
-    { "nAddFontWeightStyle",   "(JLjava/lang/String;IZ)Z", (void*)FontFamily_addFontWeightStyle },
+    { "nAddFont",              "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont },
+    { "nAddFontWeightStyle",   "(JLjava/lang/String;IIZ)Z", (void*)FontFamily_addFontWeightStyle },
     { "nAddFontFromAsset",     "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
                                            (void*)FontFamily_addFontFromAsset },
 };
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 95be3f2..6ecb3fb 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -21,6 +21,8 @@
 #include <dlfcn.h>
 #include <fcntl.h>
 
+#include <memory>
+
 #include <android_runtime/android_app_NativeActivity.h>
 #include <android_runtime/android_util_AssetManager.h>
 #include <android_runtime/android_view_Surface.h>
@@ -39,6 +41,7 @@
 #include "android_view_KeyEvent.h"
 
 #include "nativebridge/native_bridge.h"
+#include "nativeloader/native_loader.h"
 
 #include "core_jni_helpers.h"
 
@@ -255,18 +258,19 @@
 static jlong
 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
         jobject messageQueue, jstring internalDataDir, jstring obbDir,
-        jstring externalDataDir, jint sdkVersion,
-        jobject jAssetMgr, jbyteArray savedState)
-{
+        jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
+        jbyteArray savedState, jobject classLoader, jstring libraryPath,
+        jstring isolationPath) {
     if (kLogTrace) {
         ALOGD("loadNativeCode_native");
     }
 
     const char* pathStr = env->GetStringUTFChars(path, NULL);
-    NativeCode* code = NULL;
+    std::unique_ptr<NativeCode> code;
     bool needNativeBridge = false;
 
-    void* handle = dlopen(pathStr, RTLD_LAZY);
+    void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader,
+                                     libraryPath, isolationPath);
     if (handle == NULL) {
         if (NativeBridgeIsSupported(pathStr)) {
             handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
@@ -284,26 +288,23 @@
             funcPtr = dlsym(handle, funcStr);
         }
 
-        code = new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr);
+        code.reset(new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr));
         env->ReleaseStringUTFChars(funcName, funcStr);
 
         if (code->createActivityFunc == NULL) {
             ALOGW("ANativeActivity_onCreate not found");
-            delete code;
             return 0;
         }
         
         code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue);
         if (code->messageQueue == NULL) {
             ALOGW("Unable to retrieve native MessageQueue");
-            delete code;
             return 0;
         }
         
         int msgpipe[2];
         if (pipe(msgpipe)) {
             ALOGW("could not create pipe: %s", strerror(errno));
-            delete code;
             return 0;
         }
         code->mainWorkRead = msgpipe[0];
@@ -315,12 +316,11 @@
         SLOGW_IF(result != 0, "Could not make main work write pipe "
                 "non-blocking: %s", strerror(errno));
         code->messageQueue->getLooper()->addFd(
-                code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
+                code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code.get());
         
         code->ANativeActivity::callbacks = &code->callbacks;
         if (env->GetJavaVM(&code->vm) < 0) {
             ALOGW("NativeActivity GetJavaVM failed");
-            delete code;
             return 0;
         }
         code->env = env;
@@ -356,14 +356,18 @@
             rawSavedSize = env->GetArrayLength(savedState);
         }
 
-        code->createActivityFunc(code, rawSavedState, rawSavedSize);
+        code->createActivityFunc(code.get(), rawSavedState, rawSavedSize);
 
         if (rawSavedState != NULL) {
             env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
         }
     }
     
-    return (jlong)code;
+    return (jlong)code.release();
+}
+
+static jstring getDlError_native(JNIEnv* env, jobject clazz) {
+  return env->NewStringUTF(dlerror());
 }
 
 static void
@@ -651,8 +655,10 @@
 }
 
 static const JNINativeMethod g_methods[] = {
-    { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)J",
-            (void*)loadNativeCode_native },
+    { "loadNativeCode",
+        "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)J",
+        (void*)loadNativeCode_native },
+    { "getDlError", "()Ljava/lang/String;", (void*) getDlError_native },
     { "unloadNativeCode", "(J)V", (void*)unloadNativeCode_native },
     { "onStartNative", "(J)V", (void*)onStart_native },
     { "onResumeNative", "(J)V", (void*)onResume_native },
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 1ee7ea8..2488111 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -595,6 +595,36 @@
     MEMINFO_COUNT
 };
 
+static long long get_zram_mem_used()
+{
+#define ZRAM_SYSFS "/sys/block/zram0/"
+    FILE *f = fopen(ZRAM_SYSFS "mm_stat", "r");
+    if (f) {
+        long long mem_used_total = 0;
+
+        int matched = fscanf(f, "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total);
+        if (matched != 1)
+            ALOGW("failed to parse " ZRAM_SYSFS "mm_stat");
+
+        fclose(f);
+        return mem_used_total;
+    }
+
+    f = fopen(ZRAM_SYSFS "mem_used_total", "r");
+    if (f) {
+        long long mem_used_total = 0;
+
+        int matched = fscanf(f, "%lld", &mem_used_total);
+        if (matched != 1)
+            ALOGW("failed to parse " ZRAM_SYSFS "mem_used_total");
+
+        fclose(f);
+        return mem_used_total;
+    }
+
+    return 0;
+}
+
 static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
 {
     char buffer[1024];
@@ -680,15 +710,7 @@
         if (*p) p++;
     }
 
-    fd = open("/sys/block/zram0/mem_used_total", O_RDONLY);
-    if (fd >= 0) {
-        len = read(fd, buffer, sizeof(buffer)-1);
-        close(fd);
-        if (len > 0) {
-            buffer[len] = 0;
-            mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer)/1024;
-        }
-    }
+    mem[MEMINFO_ZRAM_TOTAL] = get_zram_mem_used() / 1024;
     // Recompute Vmalloc Used since the value in meminfo
     // doesn't account for I/O remapping which doesn't use RAM.
     mem[MEMINFO_VMALLOC_USED] = get_allocated_vmalloc_memory() / 1024;
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index d7e2c02..71be52e 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -65,33 +65,34 @@
         return OK;
     }
 
-    jobject loadedPointerIconObj = env->CallObjectMethod(pointerIconObj,
-            gPointerIconClassInfo.load, contextObj);
-    if (env->ExceptionCheck() || !loadedPointerIconObj) {
+    ScopedLocalRef<jobject> loadedPointerIconObj(env, env->CallObjectMethod(pointerIconObj,
+            gPointerIconClassInfo.load, contextObj));
+    if (env->ExceptionCheck() || !loadedPointerIconObj.get()) {
         ALOGW("An exception occurred while loading a pointer icon.");
         LOGW_EX(env);
         env->ExceptionClear();
         return UNKNOWN_ERROR;
     }
+    return android_view_PointerIcon_getLoadedIcon(env, loadedPointerIconObj.get(), outPointerIcon);
+}
 
-    outPointerIcon->style = env->GetIntField(loadedPointerIconObj,
-            gPointerIconClassInfo.mStyle);
-    outPointerIcon->hotSpotX = env->GetFloatField(loadedPointerIconObj,
-            gPointerIconClassInfo.mHotSpotX);
-    outPointerIcon->hotSpotY = env->GetFloatField(loadedPointerIconObj,
-            gPointerIconClassInfo.mHotSpotY);
+status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
+        PointerIcon* outPointerIcon) {
+    outPointerIcon->style = env->GetIntField(pointerIconObj, gPointerIconClassInfo.mStyle);
+    outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
+    outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);
 
-    jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap);
-    if (bitmapObj) {
-        GraphicsJNI::getSkBitmap(env, bitmapObj, &(outPointerIcon->bitmap));
-        env->DeleteLocalRef(bitmapObj);
+    ScopedLocalRef<jobject> bitmapObj(
+            env, env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmap));
+    if (bitmapObj.get()) {
+        GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmap));
     }
 
     ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>(
-            env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmapFrames)));
+            env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmapFrames)));
     if (bitmapFramesObj.get()) {
         outPointerIcon->durationPerFrame = env->GetIntField(
-                loadedPointerIconObj, gPointerIconClassInfo.mDurationPerFrame);
+                pointerIconObj, gPointerIconClassInfo.mDurationPerFrame);
         jsize size = env->GetArrayLength(bitmapFramesObj.get());
         outPointerIcon->bitmapFrames.resize(size);
         for (jsize i = 0; i < size; ++i) {
@@ -100,7 +101,6 @@
         }
     }
 
-    env->DeleteLocalRef(loadedPointerIconObj);
     return OK;
 }
 
diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h
index ca08085..00bdfb4 100644
--- a/core/jni/android_view_PointerIcon.h
+++ b/core/jni/android_view_PointerIcon.h
@@ -97,6 +97,11 @@
 extern status_t android_view_PointerIcon_load(JNIEnv* env,
         jobject pointerIconObj, jobject contextObj, PointerIcon* outPointerIcon);
 
+/* Obtain the data of pointerIconObj and put to outPointerIcon. */
+extern status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
+        PointerIcon* outPointerIcon);
+
+
 /* Loads the bitmap associated with a pointer icon by style.
  * If pointerIconObj is NULL, returns OK and a pointer icon with POINTER_ICON_STYLE_NULL. */
 extern status_t android_view_PointerIcon_loadSystemIcon(JNIEnv* env,
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ff51e4e..f6e68c4 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -149,7 +149,9 @@
         case PublicFormat::DEPTH16:
             return HAL_DATASPACE_DEPTH;
         case PublicFormat::RAW_SENSOR:
+        case PublicFormat::RAW_PRIVATE:
         case PublicFormat::RAW10:
+        case PublicFormat::RAW12:
             return HAL_DATASPACE_ARBITRARY;
         case PublicFormat::YUV_420_888:
         case PublicFormat::NV21:
@@ -170,6 +172,7 @@
         case HAL_PIXEL_FORMAT_RGB_565:
         case HAL_PIXEL_FORMAT_Y8:
         case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_RAW12:
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
         case HAL_PIXEL_FORMAT_YV12:
             // Enums overlap in both name and value
@@ -177,6 +180,9 @@
         case HAL_PIXEL_FORMAT_RAW16:
             // Name differs, though value is the same
             return PublicFormat::RAW_SENSOR;
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Name differs, though value is the same
+            return PublicFormat::RAW_PRIVATE;
         case HAL_PIXEL_FORMAT_YCbCr_422_SP:
             // Name differs, though the value is the same
             return PublicFormat::NV16;
@@ -212,7 +218,6 @@
             }
             break;
         case HAL_PIXEL_FORMAT_BGRA_8888:
-        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
             // Not defined in public API
             return PublicFormat::UNKNOWN;
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 73c7487..96d150b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -581,7 +581,7 @@
     UnsetSigChldHandler();
 
     env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
-                              is_system_server ? NULL : instructionSet);
+                              is_system_server, instructionSet);
     if (env->ExceptionCheck()) {
       RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
     }
@@ -652,7 +652,7 @@
 int register_com_android_internal_os_Zygote(JNIEnv* env) {
   gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName));
   gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
-                                                   "(ILjava/lang/String;)V");
+                                                   "(IZLjava/lang/String;)V");
 
   return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
 }
diff --git a/core/res/Android.mk b/core/res/Android.mk
index cfc791d..a1bef83 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -23,6 +23,7 @@
 # Tell aapt to create "extending (non-application)" resource IDs,
 # since these resources will be used by many apps.
 LOCAL_AAPT_FLAGS := -x
+LOCAL_AAPT_FLAGS += --private-symbols com.android.internal
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5251b20..de7f6ed 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -277,6 +277,7 @@
     <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
     <protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" />
+    <protected-broadcast android:name="android.intent.action.BUGREPORT_STARTED" />
 
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
@@ -368,6 +369,22 @@
     <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
     <protected-broadcast android:name="wifi_scan_available" />
 
+    <protected-broadcast android:name="action.cne.started" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+    <protected-broadcast android:name="android.content.jobscheduler.JOB_DEADLINE_EXPIRED" />
+    <protected-broadcast android:name="android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW" />
+    <protected-broadcast android:name="android.location.HIGH_POWER_REQUEST_CHANGE" />
+    <protected-broadcast android:name="android.location.HIGH_POWER_REQUEST_CHANGE" />
+    <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_SUPL" />
+    <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
+    <protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
+    <protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
+    <protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" />
+    <protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" />
+    <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
+    <protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" />
+    <protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -642,14 +659,14 @@
 
     <!-- Allows an application to access the IMS call service: making and
          modifying a call
-        <p>Protection level: signature|system
+        <p>Protection level: signature|privileged
         @hide
     -->
     <permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE"
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_accessImsCallService"
         android:description="@string/permdesc_accessImsCallService"
-        android:protectionLevel="signature|system" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to read the user's call log.
          <p class="note"><strong>Note:</strong> If your app uses the
@@ -926,7 +943,7 @@
     <!-- @SystemApi @hide Allows an application to modify cell broadcasts through the content provider.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MODIFY_CELL_BROADCASTS"
-                android:protectionLevel="signature|system" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- =============================================================== -->
     <!-- Permissions for setting the device alarm                        -->
@@ -947,16 +964,16 @@
     <eat-comment />
 
     <!-- Allows an application to modify and remove existing voicemails in the system
-        <p>Protection level: system|signature
+        <p>Protection level: signature|privileged
     -->
     <permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to read voicemails in the system.
-         <p>Protection level: system|signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
@@ -1092,7 +1109,7 @@
          allow or disallow phonebook access or message access.
          This is not available to third party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Control access to email providers exclusively for Bluetooth
          @hide
@@ -1330,26 +1347,26 @@
          corresponds to a device SIM.
          @hide -->
     <permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_CALL_PROVIDER.
          @hide -->
     <permission android:name="android.permission.REGISTER_CALL_PROVIDER"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_CONNECTION_MANAGER
          @hide -->
     <permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.InCallService},
          to ensure that only the system can bind to it.
-         <p>Protection level: system|signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
@@ -1358,24 +1375,24 @@
          @SystemApi
          @hide -->
     <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
-         <p>Protection level: system|signature
+         <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to control the in-call experience.
          @hide -->
     <permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to receive STK related commands.
          @hide -->
     <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
@@ -1730,12 +1747,12 @@
     <!-- @SystemApi Allows mounting and unmounting file systems for removable storage.
     <p>Not for use by third-party applications.-->
     <permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows formatting file systems for removable storage.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @hide -->
     <permission android:name="android.permission.STORAGE_INTERNAL"
@@ -2398,7 +2415,7 @@
          access the network and acquire wakelocks.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Permission an application must hold in order to use
          {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
@@ -2612,7 +2629,7 @@
 
     <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_FINGERPRINT"
-        android:protectionLevel="system|signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
     <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_focused.xml b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
index d7b167dd..0794ed3 100644
--- a/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
@@ -23,7 +23,7 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#FFFFFFFF"
+            android:fillColor="#ff000000"
             android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
index e2e81b9..bd1db51 100644
--- a/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
@@ -23,7 +23,7 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#33FFFFFF"
+            android:fillColor="#33000000"
             android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_focused.xml b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
index 0794ed3..d7b167dd 100644
--- a/core/res/res/drawable/ic_decor_close_button_light_focused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
@@ -23,7 +23,7 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#ff000000"
+            android:fillColor="#FFFFFFFF"
             android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
index bd1db51..e2e81b9 100644
--- a/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
@@ -23,7 +23,7 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#33000000"
+            android:fillColor="#33FFFFFF"
             android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
index 73d808b..c23390e 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
@@ -23,10 +23,10 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#FFFFFFFF"
+            android:fillColor="#FF000000"
             android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
         <path
-            android:fillColor="#B2FFFFFF"
+            android:fillColor="#B2000000"
             android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
index dc79e10..a194a39 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
@@ -23,10 +23,10 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#33FFFFFF"
+            android:fillColor="#33000000"
             android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
         <path
-            android:fillColor="#33FFFFFF"
+            android:fillColor="#33000000"
             android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
index c23390e..73d808b 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
@@ -23,10 +23,10 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#FF000000"
+            android:fillColor="#FFFFFFFF"
             android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
         <path
-            android:fillColor="#B2000000"
+            android:fillColor="#B2FFFFFF"
             android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
     </group>
 </vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
index a194a39..dc79e10 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
@@ -23,10 +23,10 @@
            android:translateX="8.0"
            android:translateY="8.0" >
         <path
-            android:fillColor="#33000000"
+            android:fillColor="#33FFFFFF"
             android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
         <path
-            android:fillColor="#33000000"
+            android:fillColor="#33FFFFFF"
             android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
     </group>
 </vector>
diff --git a/core/res/res/layout/decor_caption.xml b/core/res/res/layout/decor_caption.xml
new file mode 100644
index 0000000..0246736
--- /dev/null
+++ b/core/res/res/layout/decor_caption.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:descendantFocusability="beforeDescendants" >
+    <LinearLayout
+            android:id="@+id/caption"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="end"
+            android:background="@drawable/decor_caption_title"
+            android:focusable="false"
+            android:descendantFocusability="blocksDescendants" >
+        <Button
+                android:id="@+id/maximize_window"
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:layout_margin="5dp"
+                android:padding="4dp"
+                android:layout_gravity="center_vertical|end"
+                android:contentDescription="@string/maximize_button_text"
+                android:background="@drawable/decor_maximize_button_dark" />
+        <Button
+                android:id="@+id/close_window"
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:layout_margin="5dp"
+                android:padding="4dp"
+                android:layout_gravity="center_vertical|end"
+                android:contentDescription="@string/close_button_text"
+                android:background="@drawable/decor_close_button_dark" />
+    </LinearLayout>
+</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/layout/decor_caption_dark.xml b/core/res/res/layout/decor_caption_dark.xml
deleted file mode 100644
index 95d2289..0000000
--- a/core/res/res/layout/decor_caption_dark.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:descendantFocusability="beforeDescendants" >
-    <LinearLayout
-        android:id="@+id/caption"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="end"
-        android:background="@drawable/decor_caption_title"
-        android:focusable="false"
-        android:descendantFocusability="blocksDescendants" >
-        <Button
-            android:id="@+id/maximize_window"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_margin="5dp"
-            android:padding="4dp"
-            android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/maximize_button_text"
-            android:background="@drawable/decor_maximize_button_dark" />
-        <Button
-            android:id="@+id/close_window"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_margin="5dp"
-            android:padding="4dp"
-            android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/close_button_text"
-            android:background="@drawable/decor_close_button_dark" />
-    </LinearLayout>
-</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/layout/decor_caption_light.xml b/core/res/res/layout/decor_caption_light.xml
deleted file mode 100644
index f0f661e..0000000
--- a/core/res/res/layout/decor_caption_light.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:descendantFocusability="beforeDescendants" >
-    <LinearLayout
-        android:id="@+id/caption"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="end"
-        android:background="@drawable/decor_caption_title"
-        android:focusable="false"
-        android:descendantFocusability="blocksDescendants" >
-        <Button
-            android:id="@+id/maximize_window"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_margin="5dp"
-            android:padding="4dp"
-            android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/maximize_button_text"
-            android:background="@drawable/decor_maximize_button_light" />
-        <Button
-            android:id="@+id/close_window"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_margin="5dp"
-            android:padding="4dp"
-            android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/close_button_text"
-            android:background="@drawable/decor_close_button_light" />
-    </LinearLayout>
-</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index 62602d8..398f52d 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -22,7 +22,7 @@
     android:layout_height="48dp"
     android:layout_gravity="center"
     android:layout_marginStart="4dp"
-    android:textColor="@color/secondary_text_material_light"
+    android:textColor="@color/notification_default_color"
     android:singleLine="true"
     android:ellipsize="end"
     android:background="@drawable/notification_material_action_background"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index eaf82fb..cf4f18d 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Opgedateer deur jou administrateur"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deur jou administrateur uitgevee"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Om batterylewe te help verbeter, verminder batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Geblokkeer: Moet nooit hierdie kennisgewings wys nie"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Laag: Wys sonder klank aan die onderkant van die kennisgewinglys"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normaal: Wys hierdie kennisgewings sonder klank"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 03dbcae..4a35fb4 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"በአስተዳዳሪዎ ተዘምኗል"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"የባትሪ ዕድሜን ለማሻሻል ማገዝ እንዲቻል፣ ኢሜይል፣ መልዕክት አላላክ እና ሌሎች በማመሳሰል ላይ የሚመረኮዙ መተግበሪያዎች እርስዎ ካልከፈቱዋቸው በቀር አይዘምኑም።\n\nየባትሪ ኃይል ቆጣቢ የእርስዎ መሣሪያ ኃይል በሚሞላበት ጊዜ በራስ-ሰር ይጠፋል።"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"የታገደ፦ እነኝህን ማሳወቂያዎች ፈፅሞ አታሳይ"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"ዝቅተኛ፦ በጸጥታ የማሳወቂያ ዝርዝር የታችኛውን ክፍል አሳይ"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"መደበኛ፦ በጸጥታ እነኝህን ማሳወቂያዎች አሳይ"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"የተለያዩ"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b103b1b..c18fc4a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1476,6 +1476,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"تم التحديث بواسطة المشرف"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"تم حذف الحزمة عن طريق المشرف"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"للمساعدة في تحسين عمر البطارية، يساعد موفر البطارية في تقليل أداء الجهاز ويفرض قيدًا على الاهتزاز وخدمات الموقع ومعظم بيانات الخلفية. قد لا يتم تحديث البريد الإلكتروني والمراسلة والتطبيقات الأخرى التي تعتمد على المزامنة ما لم تفتحها.\n\nيتم إيقاف موفر البطارية تلقائيًا أثناء شحن الجهاز."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"الأهمية"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"محظور: عدم عرض هذه الإشعارات مطلقًا"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"منخفض الأهمية: عرض بأسفل قائمة الإشعارات وبدون تنبيه صوتي"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"عادي: عرض هذه الإشعارات بدون تنبيه صوتي"</string>
@@ -1582,4 +1583,6 @@
       <item quantity="one">تم تحديد <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"متنوعة"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"لقد عيَّنت أهمية هذه الإشعارات."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 920068b..5de0b59 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Sizin administrator tərəfindən yeniləndi"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratorunuz tərəfindən silinib"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Batareyanın istismar müddətini təkmilləşdirmək üçün batareya qənaəti cihazınızın məhsuldarlığını azaldır və titrətmə, məkan xidmətləri və ən son fon məlumatlarını məhdudlaşdırır. Sinxronlaşmaya arxayın olan e-poçt, mesajlaşma və digər proqramlar siz onları açmayana kimi yenilənməyə bilər.\n\nCihazınız doldurulan zaman batareya qənaəti avtomatik olaraq sönür."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Əhəmiyyət"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blok edildi: Bu bildirişləri heç vaxt göstərməyin"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Alçaq: Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Bu bildişləri səssiz göstərin"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Müxtəlif"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 88b261e..fc0317a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Актуализирано от администратора ви"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Изтрито от администратора ви"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"С цел удължаване на живота на батерията режимът за запазването й намалява ефективността на устройството ви и ограничава вибрирането, услугите за местоположение и повечето данни на заден план. Приложенията за електронна поща, съобщения и др., които разчитат на синхронизиране, може да не се актуализират, освен ако не ги отворите.\n\nРежимът за запазване на батерията се изключва автоматично, когато устройството ви се зарежда."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Важност"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирано: Тези известия никога да не се показват"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Маловажно: Показване без звуков сигнал в долната част на списъка с известия"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Нормално: Тези известия да се показват без звуков сигнал"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one">Избрахте <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Други"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Зададохте важността на тези известия."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Това е важно заради участващите хора."</string>
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 91244e6..bbec615 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"আপনার প্রশাসক দ্বারা আপডেট করা হয়েছে"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"আপনার প্রশাসক দ্বারা মুছে ফেলা হয়েছে"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ব্যাটরির লাইফ উন্নত করতে সহায়তা করতে, ব্যাটারি সাশ্রয়কারী আপনার ডিভাইসের কার্যসম্পাদনা হ্রাস করে এবং কম্পন, অবস্থান পরিষেবাসমূহ এবং অধিকাংশ ব্যাকগ্রাউন্ড ডেটা সীমিত করে৷ ইমেল, বার্তাপ্রেরণ এবং অন্যান্য অ্যাপ্লিকেশানগুলিকে যেগুলি সিঙ্কের উপর নির্ভর করে সেগুলিকে আপনি না খোলা পর্যন্ত নাও আপডেট হতে পারে৷\n\nআপনার ডিভাইসটিকে যখন চার্জ করা হয় তখন ব্যাটারি সাশ্রয়কারী স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যায়৷"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"অবরুদ্ধ: এই বিজ্ঞপ্তিগুলি কখনই দেখানো হবে না"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"নিম্ন: বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে প্রদর্শন করা হয়"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"সাধারন: এই বিজ্ঞপ্তিগুলি নিঃশব্দে প্রদর্শন করা হয়"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"বিবিধ"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0d2b46c..13109f5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"L\'administrador l\'ha actualitzat"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"L\'administrador ho ha suprimit"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Per tal d\'augmentar la durada de la bateria, la funció d\'estalvi de bateria redueix el rendiment del dispositiu i en limita la vibració i la majoria de dades en segon pla. És possible que el correu electrònic, la missatgeria i la resta d\'aplicacions que se sincronitzen amb freqüència no s\'actualitzin llevat que les obris.\n\nL\'estalvi de bateria es desactiva automàticament mentre el dispositiu s\'està carregant."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquejada: no mostra mai aquestes notificacions"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostra de manera silenciosa a la part inferior de la llista de notificacions"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostra aquestes notificacions de manera silenciosa"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one">Seleccionats: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Altres"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4c554bc..ea94aff 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1458,6 +1458,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizováno administrátorem"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Smazáno administrátorem"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Spořič baterie za účelem prodloužení výdrže baterie snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokováno: Tato oznámení nikdy nezobrazovat"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Nízká: Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normální: Tato oznámení zobrazovat bez zvukového upozornění"</string>
@@ -1546,4 +1548,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> položka</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Různé"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 850b8a2..73e9990 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -998,11 +998,11 @@
     <string name="sms_control_no" msgid="625438561395534982">"Afvis"</string>
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vil sende en besked til &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Dette "<b>"kan medføre gebyrer"</b>" på din mobilkonto."</string>
-    <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Dette vil medføre gebyrer på din mobilkonto."</b></string>
+    <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Dette kan koste mere end almindelig sms-takst."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Send"</string>
     <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Annuller"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Husk mit valg"</string>
-    <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Du kan ændre dette senere i Indstillinger &gt; Apps"</string>
+    <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Du kan altid ændre dette i Indstillinger &gt; Apps"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Tillad altid"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Tillad aldrig"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort blev fjernet"</string>
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Opdateret af administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Slettet af din administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen slukker automatisk, når enheden oplader."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeret: Vis aldrig disse underretninger"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Lav: Vis lydløst nederst på listen over underretninger"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Vis disse underretninger lydløst"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ab45504..a1bd45c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Von Ihrem Administrator aktualisiert"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Von Ihrem Administrator gelöscht"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf Ihrem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn Ihr Gerät aufgeladen wird."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blockiert: Keine Benachrichtigungen anzeigen"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Niedrig: Benachrichtigungen ganz unten in der Benachrichtigungsliste und ohne Ton anzeigen"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Benachrichtigungen ohne Ton anzeigen"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Sonstige"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index d5fdd29..f0b1bf9 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ενημερώθηκε από το διαχειριστή σας"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Διαγράφηκε από το διαχειριστή σας"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Προκειμένου να βελτιώσει τη διάρκεια ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας μειώνει την απόδοση της συσκευής σας και περιορίζει λειτουργίες όπως η δόνηση, οι υπηρεσίες τοποθεσίας και τα περισσότερα δεδομένα παρασκηνίου. Το ηλεκτρονικό ταχυδρομείο, η ανταλλαγή μηνυμάτων και άλλες εφαρμογές που βασίζονται στο συγχρονισμό ενδέχεται να μην ενημερώνονται έως ότου τις ανοίξετε.\n\nΗ Εξοικονόμηση μπαταρίας απενεργοποιείται αυτόματα όταν η συσκευή σας φορτίζει."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Αποκλεισμένες: Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Χαμηλής βαρύτητας: Να εμφανίζονται στο κάτω τμήμα της λίστας ειδοποιήσεων χωρίς τη συνοδεία ήχου"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Κανονική βαρύτητα: Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one">Επιλέχτηκε <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Διάφορα"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 6c20763..9350ef7 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 6c20763..9350ef7 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 6c20763..9350ef7 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Miscellaneous"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"You set the importance of these notifications."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 4e2029f..7369278 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por el administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Lo eliminó el administrador."</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que el correo electrónico, la mensajería y otras aplicaciones que se basan en la sincronización no puedan actualizarse, a menos que los abras.\n\nEl ahorro de batería se desactiva de forma automática cuando el dispositivo se está cargando."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: no mostrar nunca estas notificaciones"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baja: mostrar en la parte inferior de la lista de notificación sin emitir sonido"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificaciones de manera silenciosa"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 4868f6b..420981b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado por tu administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: no mostrar estas notificaciones"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baja: mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificaciones de forma silenciosa"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 3bbdcdf..ffaa4df 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Värskendas administraator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Kustutas teie administraator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Aku kestuse parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibratsiooni, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui te need avate.\n\nAkusäästja lülitatakse seadme laadimise ajal automaatselt välja."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeeritud: ära kunagi näita neid märguandeid"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Madal: kuva vaikselt märguannete loendi allosas"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Tavaline: kuva need märguanded vaikselt"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Mitmesugust"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 13c8720..d32a0818 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratzaileak ezabatu du"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Bateriak gehiago iraun dezan, bateria-aurrezleak gailuaren funtzionamendua, dardara,  kokapen-zerbitzuak eta atzeko planoko datuen erabilera gehiena mugatzen ditu. Posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak ez dira eguneratuko ireki ezean.\n\nGailua kargatzen ezarri orduko desaktibatzen da bateria-aurrezlea."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeatuta: ez erakutsi jakinarazpen hauek"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Txikia: erakutsi jakinarazpen hauek zerrendaren behealdean"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normala: erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Askotarikoak"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 9cbb29b..cf6df8e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -674,7 +674,7 @@
     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"‏سیم کارت شما به‌طور دائم غیر فعال شده است. \nبرای داشتن سیم کارت دیگر با ارائه‎دهنده سرویس بی‎سیم خود تماس بگیرید."</string>
     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"آهنگ قبلی"</string>
     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"آهنگ بعدی"</string>
-    <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"توقف موقت"</string>
+    <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"مکث"</string>
     <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"پخش"</string>
     <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"توقف"</string>
     <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"عقب بردن"</string>
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"توسط سرپرست شما به‌روزرسانی شد"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"توسط سرپرستتان حذف شد"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود عمر باتری، بهینه‌سازی باتری عملکرد دستگاهتان را کاهش می‌دهد و لرزش، سرویس‌های مبتنی بر مکان، و دسترسی به اکثر داده‌ها در پس‌زمینه را محدود می‌کند. ایمیل، پیام‌رسانی و برنامه‌های دیگری که به همگام‌سازی وابسته‌اند، تا زمانی‌که آن‌ها را باز نکنید نمی‌توانند به‌روز شوند.\n\nبهینه‌سازی باتری به‌صورت خودکار در هنگام شارژ شدن دستگاه خاموش می‌شود."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"مسدود: هرگز این اعلان‌ها نشان داده نشود"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"پایین: بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"عادی: این اعلان‌ها بدون صدا نشان داده شود"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقه"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 34b5fad..eea796e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Järjestelmänvalvojasi on päivittänyt paketin."</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Järjestelmänvalvoja on poistanut paketin."</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Jos haluat parantaa akun kestoa, virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Estetty: älä koskaan näytä näitä ilmoituksia."</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Matala: näytä nämä ilmoitukset huomaamattomasti luettelon alaosassa."</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Tavallinen: näytä nämä ilmoitukset huomaamattomasti."</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Muut"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9dad4c0..3afdcc0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la pile, la fonction d\'économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\n L\'économiseur d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquée : ne jamais afficher ces notifications"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Faible : afficher en mode silencieux au bas de la liste de notifications"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normale : afficher ces notifications en mode silencieux"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index dc08738..7ea8283 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances et désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. Les messageries électroniques ou autres applications utilisant la synchronisation pourraient ne pas se mettre à jour, sauf si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquée : ne jamais afficher ces notifications"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Faible : afficher en mode silencieux au bas de la liste de notifications"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normale : afficher ces notifications en mode silencieux"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 02ee7b45..83ba790 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado polo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado polo administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para axudar a mellorar a duración da batería, a función aforro de batería reduce o rendemento do teu dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función aforro de batería desactívase automaticamente cando pos a cargar o teu dispositivo."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: non mostrar nunca estas notificacións"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificacións de forma silenciosa"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index c1187df..bcb3321 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ થયેલ"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખેલ"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"બૅટરી આવરદા વધુ સારી કરવામાં સહાય માટે, બૅટરી સેવર તમારા ઉપકરણના પ્રદર્શનને ઘટાડે છે અને વાઇબ્રેશન, સ્થાન સેવાઓ અને મોટાભાગના પૃષ્ઠભૂમિ ડેટાને સીમિત કરે છે. ઇમેઇલ, મેસેજિંગ અને અન્ય એપ્લિકેશનો જે સમન્વયન પર આધાર રાખે છે તે તમે તેમને ખોલશો નહીં ત્યાં સુધી અપડેટ થઈ શકતી નથી.\n\nજ્યારે તમારું ઉપકરણ ચાર્જ થઈ રહ્યું હોય ત્યારે બૅટરી સેવર આપમેળે બંધ થઈ જાય છે."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"મહત્વ"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"અવરોધિત: આ સૂચનાઓ ક્યારેય બતાવશો નહીં"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"નિમ્ન: સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"સામાન્ય: આ સૂચનાઓ ચુપચાપ બતાવો"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"વિવિધ"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index e81872a..ef8be64 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"आपके नियंत्रक द्वारा अपडेट किया गया"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"आपके नियंत्रक द्वारा हटाया गया"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"बैटरी जीवन काल को बेहतर बनाने में सहायता के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन, स्‍थान सेवाओं और अधिकांश पृष्‍ठभूमि डेटा को सीमित कर देता है. हो सकता है कि ईमेल, संदेश सेवा तथा समन्‍वयन पर आधारित अन्‍य ऐप्‍स तब तक ना खुलें जब तक कि आप उन्‍हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"महत्‍व"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"अवरोधित: ये नोटिफिकेशन कभी ना दिखाएं"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"निम्‍न: नोटिफिकेशन सूची के नीचे मौन रूप से दिखाएं"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"सामान्‍य: ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f53625e..0609843 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1310,7 +1310,7 @@
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Nastavite držati s dva prsta kako biste omogućili pristupačnost."</string>
-    <string name="accessibility_enabled" msgid="1381972048564547685">"Dostupnost je omogućena."</string>
+    <string name="accessibility_enabled" msgid="1381972048564547685">"Pristupačnost je omogućena."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost otkazana."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="2871009331809089783">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1449,6 +1449,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurira vaš administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produljilo trajanje baterije, ušteda baterije smanjuje rad uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije isključuje se automatski dok se uređaj puni."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirano: nikad ne prikazuj te obavijesti"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Nisko: tiho prikaži na dnu popisa obavijesti"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Uobičajeno: prikazuj te obavijesti tiho"</string>
@@ -1528,4 +1530,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> odabranih</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 2bb8fb0..0f3b849 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Frissítette a rendszergazda"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"A rendszergazda törölte"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Az akkumulátoridő növelése érdekében az energiatakarékos mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálására számít, csak akkor frissítenek, ha megnyitja azokat.\n\nAz energiatakarékos mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Fontosság"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Letiltva: soha nem jelennek meg ezek az értesítések"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Alacsony: az értesítések az értesítési lista végén jelennek meg hangjelzés nélkül"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normál: hang nélkül jelennek meg ezek az értesítések"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Vegyes"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Ön állította be ezen értesítések fontossági szintjét."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Ez az üzenet a résztvevők miatt fontos."</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 257d435..3fbdeb9 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ադմինիստրատորը թարմացրել է այն"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Ադմինիստրատորը ջնջել է այն"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Մարտկոցի աշխատանքի ժամկետը երկարացնելու նպատակով, մարտկոցի էներգիայի խնայման գործառույթը սահմանափակում է սարքի աշխատանքը, թրթռոցը, տեղադրության ծառայությունները և հետնաշերտում աշխատող շատ գործընթացներ: Էլփոստը, հաղորդագրությունների փոխանակումը և տվյալների համաժամեցումից կախված այլ հավելվածները կարող են չթարմացվել, եթե դուք դրանք չգործարկեք:\n\nԵրբ ձեր սարքը լիցքավորվում է, մարտկոցի էներգիայի խնայման գործառույթն ինքնաշխատորեն անջատվում է:"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Արգելափակված է. Երբեք չցուցադրել այս ծանուցումները"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Ցածր. Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Նորմալ. Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Զանազան"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 6be50d5..d13168a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Diperbarui oleh administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Dihapus oleh administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan kebanyakan data latar belakang. Email, perpesanan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Tingkat Kepentingan"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Diblokir: Jangan pernah menampilkan notifikasi ini"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Rendah: Menampilkan di bagian bawah daftar notifikasi secara diam-diam"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Menampilkan notifikasi ini secara diam-diam"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Lain-Lain"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Anda menyetel tingkat kepentingan notifikasi ini."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Ini penting karena orang-orang yang terlibat."</string>
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index c2b8a8c..b362bef 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppfært af kerfisstjóranum"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eytt af kerfisstjóra"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Til að auka endingu rafhlöðunnar mun orkusparnaður draga úr afköstum tækisins og takmarka titring, staðsetningarþjónustu og megnið af bakgrunnsgögnum. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu uppfærist nema þú opnir þau.\n\nSjálfkrafa er slökkt á orkusparnaði þegar tækið er í hleðslu."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Útilokaðar: Aldrei sýna þessar tilkynningar"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Léttvægar: Sýna neðst á tilkynningalistanum án hljóðs"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Venjulegar: Sýna þessar tilkynningar án hljóðs"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Ýmislegt"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c4614fc..66e7a2a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aggiornato dall\'amministratore"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminato dall\'amministratore"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Per aumentare la durata della batteria, la funzione di risparmio energetico riduce le prestazioni del dispositivo e limita vibrazione, servizi di localizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione di risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloccato: non mostrare mai queste notifiche"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Bassa: mostra silenziosamente alla fine dell\'elenco di notifiche"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normale: mostra silenziosamente queste notifiche"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Vari"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f615187..b0c7437 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1458,6 +1458,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"עודכן על ידי מנהל המערכת שלך"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"נמחקה על ידי מנהל המערכת שלך"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"כדי לעזור בשיפור חיי הסוללה, תכונת החיסכון בסוללה מצמצמת את פעולות המכשיר ומגבילה רטט, שירותי מיקום ואת רוב נתוני הרקע. אימייל, העברת הודעות ואפליקציות אחרות המסתמכות על סנכרון עשויות שלא להתעדכן, אלא אם תפתח אותן.\n\nתכונת החיסכון בסוללה מושבתת אוטומטית כשהמכשיר בטעינה."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"חשיבות"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"חסימה: לעולם אל תציג הודעות אלה"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"נמוכה: הצג בתחתית רשימת ההודעות בלי להשמיע צליל"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"רגילה: הצג הודעות אלה בלי להשמיע צליל"</string>
@@ -1546,4 +1547,6 @@
       <item quantity="one">בחרת <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"שונות"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"אתה מגדיר את חשיבותן של הודעות אלה."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 6dd4e9a..6b3e278 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"管理者によって更新されています"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"管理者によって削除されました"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"ブロック: 今後はこの通知を表示しない"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"低: 通知リストの下にマナーモードで表示する"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"標準: この通知をマナーモードで表示する"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>件選択済み</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"その他"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 6709d92..38b2062 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"თქვენი ადმინისტრატორის მიერ წაშლილი"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ელემენტის მოქმედების ვადის გაუმჯობესებისათვის, ელემენტის დამზოგი ამცირებს თქვენი მოწყობილობის შესრულებას და ზღუდავს ვიბრაციას, ადგილმდებარეობის მომსახურებებს და ძირითად ფონურ მონაცემებს. ელ-ფოსტა, შეტყობინებები და სხვა სინქრონიზაციაზე დაყრდნობილი აპლიკაციების განახლება არ მოხდება მათ გახსნეამდე. \n\n ელემენტის დამზოგველი ავტომატურად გამოირთვება, როდესაც თქვენს მოწყობილობას დამტენთან შეაერთებთ."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"დაბლოკილი: ეს შეტყობინებები აღარასოდეს გამოჩნდება"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"დაბალი: ეს შეტყობინებები სიის ბოლოში, უხმოდ გამოჩნდება"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"ნორმალური: ეს შეტყობინებები უხმოდ გამოჩნდება"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> შერჩეული</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"სხვადასხვა"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 8d12034..6e26292 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Әкімші жаңартты"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Әкімші жойған"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Батареяның қызмет көрсету мерзімін жақсарту үшін батарея үнемдегіш құрылғының өнімділігін төмендетеді және дірілді, орынды анықтау қызметтерін және фондық деректердің көпшілігін шектейді. Электрондық пошта, хабар алмасу және синхрондауға негізделген басқа қолданбалар ашқанша жаңартылмауы мүмкін.\n\nБатарея үнемдегіш құрылғы зарядталып жатқанда автоматты түрде өшеді."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Маңыздылық"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Бұғатталған: осы хабарландыруларды ешқашан көрсетпеу"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Төмен: хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Қалыпты: осы хабарландыруларды үнсіз көрсету"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> таңдалды</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Әр түрлі"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Сіз осы хабарландырулардың маңыздылығын орнатасасыз."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Қатысты адамдарға байланысты бұл маңызды."</string>
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index dcaf305..167fa17 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1442,6 +1442,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"បានធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"បានលុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ដើម្បីជួយឲ្យថាមពលថ្មប្រសើរឡើង កម្មវិធីសន្សំសំចៃថាមពលថ្មកាត់បន្ថយប្រតិបត្តិការឧបករណ៍របស់អ្នក និងកម្រិតភាពញ័រ សេវាកម្មទីតាំង និងទិន្នន័យផ្ទៃខាងក្រោយស្ទើរតែទាំងអស់។ ការផ្ញើសារអ៊ីម៉ែល និងកម្មវិធីផ្សេងទៀតដែលពឹងផ្អែកលើការធ្វើសមកាលកម្មអាចនឹងមិនធ្វើបច្ចុប្បន្នភាពទេ លុះត្រាតែអ្នកបើកពួកវា។\n\nកម្មវិធីសន្សំសំចៃបិទដោយស្វ័យប្រវត្តិ នៅពេលដែលឧបករណ៍របស់អ្នកកំពុងសាកថ្ម។"</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"សារៈសំខាន់"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"បានរារាំង៖ កុំបង្ហាញការជូនដំណឹងទាំងនេះ"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"កម្រិតទាប៖ បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"ធម្មតា៖ បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
@@ -1512,4 +1513,6 @@
       <item quantity="one">បានជ្រើស <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"ផ្សេងៗ"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index e7ad010..0ada13af 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ನವೀಕರಿಸಲಾಗಿದೆ"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಳಿಸಲಾಗಿದೆ"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ನಿಮ್ಮ ಬ್ಯಾಟರಿಯ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು, ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ವೈಬ್ರೇಷನ್, ಸ್ಥಳ ಸೇವೆಗಳು ಹಾಗೂ ಹೆಚ್ಚಿನ ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ. ಸಿಂಕ್ ಮಾಡುವುದನ್ನು ಅವಲಂಬಿಸಿರುವ ಇಮೇಲ್, ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ, ಮತ್ತು ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ನೀವು ತೆರೆಯದ ಹೊರತು ನವೀಕರಣಗೊಳ್ಳುವುದಿಲ್ಲ.\n\nನಿಮ್ಮ ಸಾಧನವು ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ಆಫ್ ಆಗುತ್ತದೆ."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ: ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಎಂದಿಗೂ ತೋರಿಸಬೇಡ"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"ಕಡಿಮೆ: ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"ಸಾಮಾನ್ಯ: ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"ಇತರೆ"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 85f46d1..e15df94 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"관리자에 의해 업데이트됨"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"관리자가 삭제함"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"배터리 수명 개선을 위해, 배터리 세이버는 기기의 성능을 줄이고 진동, 위치 서비스 및 대부분의 백그라운드 데이터를 제한합니다. 이메일, 메시지 및 동기화에 의존하는 기타 앱은 앱을 열 때까지 업데이트되지 않을 수 있습니다.\n\n배터리 세이버는 기기를 충전 중일 때는 자동으로 사용 중지됩니다."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"차단: 알림 다시 표시 안함"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"낮음: 알림 목록 하단에 무음으로 표시"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"일반: 무음으로 알림 표시"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"기타"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index bb1cd7f..af81c88 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1441,9 +1441,11 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Администраторуңуз тарабынан жок кылынган"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Батареянын өмүрүн узартуу үчүн, батареяны үнөмдөгүч түзмөгүңүздүн ишинин майнаптуулугун азайтып, дирилдөө, жайгашкан жерди аныктоо кызматтары жана фондук дайындардын көпчүлүгүн чектеп коёт. Электрондук почта, билдирүү жазышуу жана башка шайкештештирүүгө байланыштуу колдонмолор ачылмайынча жаңыртылбай калышы мүмкүн.\n\nБатарея үнөмдөгүч түзмөгүңүз кубатталып жатканда автоматтык түрдө өчүп калат."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Бөгөттөлгөн: Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Төмөн: Эскертмелер тизмесинин эң ылдыйында көрсөтүлсүн"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Кадимки: Бул эскертмелер акырын көрсөтүлсүн"</string>
+    <string name="notification_importance_low" msgid="6447640449918427187">"Төмөн: Эскертмелер тизмесинин эң ылдыйында үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_default" msgid="7991157697609575271">"Кадимки: Бул эскертмелер үнсүз көрсөтүлсүн"</string>
     <string name="notification_importance_high" msgid="3152238637737215654">"Жогору: Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
     <string name="notification_importance_max" msgid="1153693080467904474">"Шашылыш: Үн менен коштолуп, экранга чыгарылсын"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
@@ -1511,4 +1513,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Калган-каткандар"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index bc58ea6..723a28a 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ອັບ​ເດດ​ໂດຍ​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ແລ້ວ"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"ຖືກ​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ລຶບ​ໄປ​ແລ້ວ"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ເພື່ອ​ຊ່ວຍ​ເພີ່ມ​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ, ຕົວ​ປະ​ຢັດ​ໄຟ​ແບັດ​ເຕີ​ຣີ​ຫຼຸດ​ປະ​ສິດ​ທິ​ພາບ​ການ​ເຮັດ​ວຽກ​ຂອງ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ລົງ ແລະ​ຈຳ​ກັດ​ການ​ສັ່ນ, ການ​ບໍ​ລິ​ການ​ຫາທີ່ຕັ້ງ, ແລະ​ຂໍ້​ມູນ​ພື້ນ​ຫຼັງ​ເກືອບ​ທັງ​ໝົດ. ອີ​ເມວ, ການ​ສົ່ງ​ຂໍ້​ຄວາມ, ແລະ​ແອັບອື່ນໆ​ທີ່ອາ​ໄສການ​ຊິງ​ຄ໌​ອາດ​ຈະ​ບໍ່​ອັບ​ເດດ ນອກ​ຈາກວ່າ​ທ່ານ​ເປີດ​ມັນ.\n\nຕົວ​ປະ​ຢັດ​ໄຟ​ແບັດ​ເຕີ​ຣີຈະ​ປິດ​ອັດ​ຕະ​ໂນ​ມັດ ເມື່ອ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ກຳ​ລັງ​ສາກຢູ່."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"ບລັອກແລ້ວ: ຢ່າສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"ຕໍ່າ: ສະແດງຢູ່ສ່ວນລຸ່ມຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"ປົກກະຕິ: ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"ອື່ນໆ"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b148d2c..67eff63 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1458,6 +1458,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atnaujino administratorius"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Ištrynė administratorius"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Kad tausotų akumuliatoriaus energiją akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Svarba"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Užblokuota: niekada nerodyti šių pranešimų"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Maža: tyliai rodyti pranešimų sąrašo apačioje"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Įprasta: tyliai rodyti šiuos pranešimus"</string>
@@ -1546,4 +1547,6 @@
       <item quantity="other">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Įvairūs"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Galite nustatyti šių pranešimų svarbą."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 892402b..8c87e00 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1449,6 +1449,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atjaunināja administrators"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izdzēsa jūsu administrators"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un cita veida lietotnes, kuru darbības pamatā ir datu sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms automātiski tiek izslēgts."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloķēts: nekad nerādīt šos paziņojumus"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Zemu: rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normāli: rādīt šos paziņojumus bez skaņas signāla"</string>
@@ -1528,4 +1530,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Dažādi"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 9cfa6cf..124d7d6 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1442,6 +1442,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирано од администраторот"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Избришано од администраторот"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"За да ви помогне да ја подобрите трајноста на батеријата, штедачот на батеријата ја намалува изведбата на уредот и го ограничува вибрирањето, услугите за локација и повеќето податоци од заднина. Е-поштата, испраќањето пораки и другите апликации кои се потпираат на синхронизација можеби нема да се ажурираат доколку не ги отворите.\n\nШтедачот на батеријата автоматски се исклучува кога уредот се полни."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирано: никогаш не покажувај ги овие известувања"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Ниско: покажувај ги тивко на дното на списокот со известувања"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Нормално: покажувај ги овие известувања тивко"</string>
@@ -1512,4 +1514,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 3a3ec41..842ee4a 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർ അപ്‌ഡേറ്റുചെയ്‌തു"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർ ഇല്ലാതാക്കി"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ബാറ്ററി ആയുസ്സ് മെച്ചപ്പെടുത്താൻ സഹായിക്കുന്നതിന്, ബാറ്ററി സേവർ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെ കുറയ്‌ക്കുകയും വൈബ്രേഷനെയും മിക്ക പശ്ചാത്തല വിവരത്തെയും പരിമിതപ്പെടുത്തുകയും ചെയ്യുന്നു. ഇമെയിൽ, സന്ദേശമയയ്‌ക്കൽ, സമന്വയിപ്പിക്കലിനെ ആശ്രയിച്ചുള്ള മറ്റ് അപ്ലിക്കേഷനുകൾ എന്നിവ നിങ്ങൾ തുറക്കുന്നതുവരെ അപ്‌ഡേറ്റുചെയ്യാനിടയില്ല.\n\nനിങ്ങളുടെ ഉപകരണം ചാർജ്ജുചെയ്യുമ്പോൾ ബാറ്ററി സേവർ സ്വയം ഓഫാകും."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"പ്രാധാന്യം"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"ബ്ലോക്കുചെയ്തു: ഈ അറിയിപ്പുകൾ ഒരിക്കലും കാണിക്കരുത്"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"താഴ്ന്നത്: അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"സാധാരണം: ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"പലവക"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള്‍ ഇത് പ്രധാനപ്പെട്ടതാണ്‌."</string>
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index ab2285b..d989270 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Танай админ шинэчилсэн"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Таны админ устгасан байна"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Батарей хадгалах функц нь таны төхөөрөмжийн цэнэгийг хадгалахын тулд гүйцэтгэлийг багасгаж, чичрэлтийг бууруулж, байршлын үйлчилгээнүүд болон бусад өгөгдлийн хэмжээг багасгадаг юм. И-мэйл, мессеж болон бусад синхрон хийдэг апликейшнүүд дараа дахин нээгдэх хүртлээ автоматаар шинэчлэлт хийхгүй.\n\nМөн батарей хадгалах функц нь таныг төхөөрөмжөө цэнэглэх үед автоматаар унтрах юм."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Блоклосон: Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Бага: Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Ердийн: Эдгээр мэдэгдлийг дуугүй харуулах"</string>
@@ -1508,4 +1510,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Бусад"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 92f114a..c323b85 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"आपल्या प्रशासकाद्वारे अद्यतनित केले"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"आपल्या प्रशासकाद्वारे हटविले आहे"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"बॅटरीचे आयुष्य सुधारित करण्‍यात मदत करण्यासाठी, बॅटरी बचतकर्ता आपल्या डिव्हाइसचे कार्यप्रदर्शन कमी करतो आणि कंपन, स्थान सेवा आणि बराच पार्श्वभूमी डेटा मर्यादित करतो. संकालनावर अवलंबून असणारे ईमेल, संदेशन आणि इतर अ‍ॅप्स आपण उघडल्याशिवाय अद्यतनित होऊ शकत नाहीत.\n\nआपले डिव्हाइस चार्ज होत असते तेव्हा बॅटरी बचतकर्ता स्वयंचलितपणे बंद होतो."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"महत्त्व"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"अवरोधित केले: या सूचना कधीही दर्शवू नका"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"कमी: शांतपणे सूचना सूचीच्या तळाशी दर्शवा"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: या सूचना शांतपणे दर्शवा"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"संकीर्ण"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"आपण या सूचनांचे महत्त्व सेट केले."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string>
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index ab683fcb..1993819 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Dipadamkan oleh pentadbir anda"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu memperbaik hayat bateri, penjimat bateri mengurangkan prestasi peranti anda dan mengehadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung kepada penyegerakan mungkin tidak mengemas kini, melainkan anda membuka apl itu.\n\nPenjimat bateri dimatikan secara automatik semasa peranti anda sedang dicas."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Disekat: Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Rendah: Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Biasa: Tunjukkan pemberitahuan ini secara senyap"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Pelbagai"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 8709c7c..e8178e3 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"သင့်စီမံခန့်ခွဲသူမှ အဆင့်မြှင့်ထားပါသည်။"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"သင့် အက်ဒမင်အား ဖျက်ပစ်ရန်"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ဘက်ထရီသက်တမ်း ကြာရှည်ခံရန်၊ ဘက်ထရီအားထိန်းသည် သင့်ကိရိယာ၏ ဆောင်ရွက်ချက်ကို  လျှော့ပေးပြီး တုန်ခါမှု၊ တည်နေရာဝန်ဆောင်မှုများနှင့်၊ နောက်ခံဒေတာအများစုကို ကန့်သတ်ပေး၏။ စင့်လုပ်ပေးရလေ့ရှိသည့် အီးမေး၊ စာပို့ခြင်းနှင့်၊ အခြားအပလီကေးရှင်းများကို ၎င်းတို့အား သင် ဖွင့်မှသာ အဆင့်မြှင့်မွမ်းမံမည်ဖြစ်၏။ \n\n ကိရိယာအား အားသွင်းနေစဉ် ဘက်ထရီအားထိန်းအား အလိုအလျောက် ပိတ်ထားသည်။"</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"အရေးပါမှု"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"ပိတ်ဆို့ထား- ဤသတိပေးချက်များကို ဘယ်တော့မှ မပြပါနှင့်"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"နိမ့်- တိတ်ဆိတ်စွာ သတိပေးချက်များ၏ စာရင်း အောက်ပိုင်းမှာ ပြပါ"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"\'ပုံမှန်- ဤသတိပေးချက်များကို တိတ်ဆိတ်စွာ ပြပါ"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"အထွေထွေ"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"ဤအသိပေးချက်များ၏ အရေးပါမှုကိုသင်သတ်မှတ်ပြီးပါပြီ။"</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c966e38..0e0f400 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Oppdatert av administratoren"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Slettet av administratoren"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"For å forlenge batterilevetiden reduserer batterispareren ytelsen til enheten din og begrenser vibrering, posisjonstjenester og mesteparten av bakgrunnsdataene. E-post, sending av meldinger og andre apper som er avhengig av synkronisering, oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokkert: Aldri vis disse varslene"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Lavt: Vis nederst i varsellisten uten lyd"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normalt: Vis disse varslene uten lyd"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 931c880..ec13ebb 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1446,8 +1446,9 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"तपाईँको प्रशासकद्वारा अद्यावधिक गरिएको"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"तपाईँको प्रशासकद्वारा हटाइएको"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ब्याट्रीको आयु सुधार्न, ब्याट्री संरक्षकले तपाईँको यन्त्रको कार्यसम्पादन घटाउँछ र भाइब्रेसन, स्थान सेवा र बहुसंख्यक पृष्ठभूमि डेटा सीमित गर्दछ। इमेल, सन्देश, र अन्य अनुप्रयोगहरू जुन सिङ्कमा भर पर्छन् अद्यावधिक नहुन सक्छन् जबसम्म तपाईँ तिनीहरूलाई खोल्नुहुन्न\n\n ब्याट्री संरक्षक स्वत: निस्कृय हुन्छ जब तपाईँको यन्त्र चार्ज हुँदै हुन्छ।"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"रोकिएको: यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"कम: चुपचाप सूचना सूचीको फेदमा देखाउनुहोस्"</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"महत्त्व"</string>
+    <string name="notification_importance_blocked" msgid="7118826900767047125">"रोकिएका: यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
+    <string name="notification_importance_low" msgid="6447640449918427187">"न्यून: चुपचाप सूचना सूचीको फेदमा देखाउनुहोस्"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: चुपचाप यी सूचनाहरू देखाउनुहोस्"</string>
     <string name="notification_importance_high" msgid="3152238637737215654">"उच्च: सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
     <string name="notification_importance_max" msgid="1153693080467904474">"जरुरी: स्क्रिनमा झलक्क हेर्नुहोस् र आवाज निकाल्नुहोस्"</string>
@@ -1516,4 +1517,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> चयन गरियो</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरू महत्त्व सेट गर्नुहुन्छ।"</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ee4f63a..d30d836 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Geüpdatet door je beheerder"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Verwijderd door je beheerder"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Accubesparing beperkt de prestaties van je apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de accu te verlengen.\n\nAccubesparing wordt automatisch uitgeschakeld terwijl je apparaat wordt opgeladen."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Belang"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Geblokkeerd: deze meldingen nooit weergeven"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Laag: zonder geluid onder aan de lijst met meldingen weergeven"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normaal: deze meldingen zonder geluid weergeven"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diversen"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Je stelt het belang van deze meldingen in."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrijk vanwege de betrokken mensen."</string>
 </resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index ddc7b73..5a3b11a 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"ਤੁਹਾਡੇ ਪ੍ਰਬੰਧਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"ਬੈਟਰੀ ਸਮਰੱਥਾ ਨੂੰ ਬਿਹਤਰ ਸਹਾਇਤਾ ਕਰਨ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਦਾ ਪ੍ਰਦਰਸ਼ਨ ਘਟਾਉਂਦਾ ਹੈ ਅਤੇ ਵਾਈਬ੍ਰੇਸ਼ਨ, ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਅਤੇ ਜ਼ਿਆਦਾਤਰ ਪਿਛੋਕੜ ਡਾਟਾ ਨੂੰ ਸੀਮਿਤ ਕਰਦਾ ਹੈ। ਈਮੇਲ, ਮੈਸੇਜਿੰਗ ਅਤੇ ਹੋਰ ਐਪਸ, ਜੋ ਸਿੰਕਿੰਗ ਤੇ ਨਿਰਭਰ ਹਨ, ਉਹ ਉਦੋਂ ਤੱਕ ਅਪਡੇਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ ਖੋਲ੍ਹਦੇ ਨਹੀਂ।\n\nਬੈਟਰੀ ਸੇਵਰ ਆਟੋਮੈਟਿਕਲੀ ਬੰਦ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਚਾਰਜ ਹੋ ਰਹੀ ਹੁੰਦੀ ਹੈ।"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"ਬਲੌਕ ਕੀਤਾ: ਇਹ ਸੂਚਨਾਵਾਂ ਕਦੇ ਨਾ ਵਿਖਾਓ"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"ਘੱਟ: ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਵਿਖਾਓ"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"ਸਧਾਰਨ: ਇਹ ਸੂਚਨਾਵਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"ਵਿਵਿਧ"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7430d54..f206d82 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1458,6 +1458,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Zaktualizowane przez administratora"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Usunięty przez administratora"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, czat i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Zablokowana: nigdy nie pokazuj tych powiadomień"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Niska: pokazuj na dole listy powiadomień bez sygnału dźwiękowego"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normalna: pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
@@ -1546,4 +1548,8 @@
       <item quantity="one">Wybrano <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Inne"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f787499..7e33baa 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Excluído pelo seu administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: nunca mostrar essas notificações"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar essas notificações de forma silenciosa"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 826771e..f2e9402 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado pelo administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a autonomia da bateria, a poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização não podem ser atualizados exceto se os abrir.\n\nA poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Importância"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueado: nunca mostrar estas notificações"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baixo: mostrar na parte inferior da lista de notificações sem som"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificações sem som"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Definiu a importância destas notificações."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f787499..7e33baa 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Excluído pelo seu administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: nunca mostrar essas notificações"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar essas notificações de forma silenciosa"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f49d6a1..c716c74 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1449,6 +1449,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizat de un administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Șters de administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pentru a îmbunătăți autonomia bateriei, funcția de economisire a energiei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nFuncția de economisire a energiei se dezactivează automat când dispozitivul se încarcă."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocate: aceste notificări nu se afișează niciodată"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Redusă: se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normală: aceste notificări se afișează fără a se emite un sunet"</string>
@@ -1528,4 +1530,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selectat</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index cee24da..5a2dcd9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1458,6 +1458,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Обновлено администратором"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Удалено администратором"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибрации, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только когда вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Заблокировано: не показывать эти уведомления"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Низкая: показывать без звука в конце списка уведомлений"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Обычная: показывать уведомления без звука"</string>
@@ -1546,4 +1548,8 @@
       <item quantity="other">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Другое"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index c8a45eb1..8584f0d 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -1442,6 +1442,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"ඔබගේ පරිපාලක විසින් යාවත්කාලීන කරන ලදී"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"ඔබගේ පරිපාලක විසින් මකන ලද"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"බැටරි ආයු කාලය වැඩිදියුණු කිරීමට උදවු කිරීමට, බැටරි සුරැකුම ඔබේ උපාංගයේ ක්‍රියාකාරීත්වය අඩුකරන අතර කම්පනය, පිහිටීම් සේවා, සහ බොහෝමයක් පසුබිම් දත්ත සීමා කරයි. ඔබ ඒවා විවෘත නොකරන්නේ නම් මිස ඊමේල්, පණිවිඩකරණය, සහ සමමුහුර්ත කිරීම මත රඳා පවතින වෙනත් යෙදුම් යාවත්කාලීන නොවිය හැකිය.\n\nඔබේ උපාංගය ආරෝපණය වන විට බැටරි සුරැකුම ස්වයංක්‍රියව අක්‍රිය වේ."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"අවහිර කළ: මෙම දැනුම්දීම් කිසිදා නොපෙන්වන්න"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"අඩු: දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"සාමාන්‍ය: නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
@@ -1512,4 +1514,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"විවිධාකාර"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 242a844..d26dcc6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1458,6 +1458,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizované správcom"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Odstránený správcom"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"S cieľom predĺžiť výdrž batérie zníži šetrič batérie výkonnosť zariadenia a obmedzí vibrácie, služby určovania polohy a dátové prenosy na pozadí. Pošta, čet a ďalšie aplikácie, ktoré sa spoliehajú na synchronizáciu, sa možno nebudú aktualizovať, dokiaľ ich neotvoríte.\n\nPri nabíjaní zariadenia sa šetrič batérie automaticky vypne."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Dôležitosť"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokované: Tieto upozornenia nikdy nezobrazovať"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Nízke: Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normálne: Tieto upozornenia zobrazovať bez zvukového signálu"</string>
@@ -1546,4 +1547,6 @@
       <item quantity="one">Vybrané: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Rôzne"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Nastavili ste dôležitosť týchto upozornení."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 3f6769c..6746a9e 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1458,6 +1458,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Posodobil skrbnik"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisal skrbnik"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirano: nikoli ne prikaži teh obvestil"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Manj pomembno: prikaži na dnu seznama obvestil brez zvoka"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Običajno: prikaži ta obvestila brez zvoka"</string>
@@ -1546,4 +1548,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> izbranih</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 2653c71..4b1a45c 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Përditësuar nga administratori"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"U fshi nga administratori yt"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Për të përmirësuar jetëgjatësinë e baterisë, opsioni i kursimit të baterisë ul rendimentin e pajisjes tënde si dhe kufizon dridhjet dhe shumicën e të dhënave në sfond. Mail-i, mesazhet dhe aplikacionet e tjera që sinkronizohen automatikisht mund të mos përditësohen pa i hapur.\n\nKursimi i baterisë çaktivizohet automatikisht kur pajisja vihet në ngarkim."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Të bllokuara: Mos i shfaq asnjëherë këto njoftime"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Të ulëta: Shfaqi në heshtje në fund të listës së njoftimeve"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normale: Shfaqi këto njoftime në heshtje"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Të ndryshme"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 069d717..d7801b1 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1449,6 +1449,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирао је администратор"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Избрисао је ваш адмиистратор"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Да би продужила време трајања батерије, уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију можда неће да се ажурирају ако их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирана: Ова обавештења се никада не приказују"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Ниска: Приказују се у дну листе обавештења без звука"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Уобичајена: Ова обавештења се приказују без звука"</string>
@@ -1528,4 +1530,8 @@
       <item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 748257a..8986073 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppdaterat av administratören"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Paketet har raderats av administratören"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre och vibration, platstjänster samt den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Relevans"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Blockerad: Visa aldrig dessa aviseringar"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Låg: Visa längst ned i aviseringslistan – utan ljud"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Visa aviseringarna – utan ljud"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Du anger hur viktiga aviseringarna är."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Detta är viktigt på grund av personerna som deltar."</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cdb86ae..f00ff44 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1442,6 +1442,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Kimesasiswa na msimamizi wako"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Kilifutwa na msimamizi wako"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Kusaidia kuboresha muda wa matumizi ya betri, inayookoa betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali, na data nyingi ya chini chini. Barua pepe, ujumbe na programu nyingine zinazotege,ea usawazishaji huenda zisisasishwe usipozifungua.\n\nInayookoa betri hujizima kiotomatiki kifaa chako kinapokuwa kinachaji."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Imezuiwa: Usionyeshe arifa hizi kamwe"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Chini: Onyesha katika sehemu ya chini ya orodha ya arifa bila kutoa sauti"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Kawaida: Onyesha arifa hizi bila sauti"</string>
@@ -1512,4 +1514,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kimechaguliwa</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Anuwai"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 245f1ca..e419eea 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"நிர்வாகி நீக்கிவிட்டார்"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"பேட்டரி ஆயுளை மேம்படுத்த, பேட்டரி சேமிப்பான் உங்கள் சாதனத்தின் செயல்திறனைக் குறைத்து, அதிர்வு, இடச் சேவைகள் மற்றும் பெரும்பாலான பின்புலத் தரவு போன்றவற்றைக் கட்டுப்படுத்துகிறது. ஒத்திசைவைச் சார்ந்துள்ள மின்னஞ்சல், செய்தியிடல் மற்றும் பிற பயன்பாடுகள் திறக்கும்வரை, அவை புதுப்பிக்கப்படாமல் இருக்கலாம்.\n\nஉங்கள் ஃபோன் சார்ஜ் செய்யப்படும்போது, பேட்டரி சேமிப்பான் தானாகவே முடங்கும்."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"முக்கியத்துவம்"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"தடுக்கப்பட்டது: இந்த அறிவிப்புகளை ஒருபோதும் காட்டாது"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"குறைவு: ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டும்"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"இயல்பு: ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டும்"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டது</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"இதர அமைப்பு"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string>
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 1b63c2f..a6c80ad 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"మీ నిర్వాహకుడు నవీకరించారు"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"మీ నిర్వాహకులు తొలగించారు"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్‌ను, స్థాన సేవలను మరియు ఎక్కువ నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర అనువర్తనాలు మీరు వాటిని తెరిస్తే మినహా నవీకరించబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"ప్రాముఖ్యత"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"బ్లాక్ చేయబడింది: ఈ నోటిఫికేషన్‌లను ఎప్పుడూ చూపదు"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"తక్కువ: నోటిఫికేషన్‌ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"సాధారణం: ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"ఇతరాలు"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 57b9598..3576093 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"อัปเดตโดยผู้ดูแลระบบ"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"ลบโดยผู้ดูแลระบบของคุณ"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"เพื่อช่วยปรับปรุงอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"บล็อก: อย่าแสดงการแจ้งเตือนเหล่านี้"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"ต่ำ: แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"ปกติ: แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"เบ็ดเตล็ด"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8cca676..639d368 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Na-update ng iyong administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Na-delete ng iyong administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Upang matulungang pagbutihin ang tagal ng baterya, binabawasan ng pangtipid ng baterya ang pagganap ng iyong device at nililimitahan ang pag-vibrate, mga serbisyo ng lokasyon at karamihan sa data ng background. Maaaring hindi mag-update ang email, pagmemensahe at iba pang mga app na umaasa sa pagsi-sync maliban kung buksan mo ang mga iyon.\n\nAwtomatikong nag-o-off ang pangtipid ng baterya kapag nagcha-charge ang iyong device."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Naka-block: Huwag kailanman ipakita ang mga notification na ito"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Mababa: Tahimik na ipakita sa ibaba ng listahan ng mga notification"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Tahimik na ipakita ang mga notification na ito"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Iba Pa"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 60eee12..fea3e74 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Yöneticiniz tarafından güncellendi"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Yöneticiniz tarafından silindi"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pil tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken pil tasarrufu otomatik olarak kapatılır."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Engellendi: Bu bildirimleri hiçbir zaman gösterme"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Düşük: Bildirim listesinin altında sessizce göster"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Bu bildirimleri sessizce göster"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Çeşitli"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index adf6234..e38ec1d 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1458,6 +1458,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Оновлено адміністратором"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Видалив адміністратор"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Щоб подовжити час роботи акумулятора, функція заощадження заряду акумулятора знижує продуктивність пристрою, а також обмежує вібрацію, функції служб локації та передавання більшості фонових даних. Електронна пошта, чати й інші додатки, які синхронізуються, можуть не оновлюватися, доки ви їх не відкриєте.\n\nФункція заощадження заряду акумулятора автоматично вимикається під час заряджання пристрою."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Пріоритет"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Заблоковано: не показувати ці сповіщення"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Низький пріоритет: показувати ці сповіщення внизу списку без звукового сигналу"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Стандартний пріоритет: показувати ці сповіщення без звукового сигналу"</string>
@@ -1546,4 +1547,6 @@
       <item quantity="other">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Інше"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Ви вказуєте пріоритет цих сповіщень."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Важливе з огляду на учасників."</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 54af31e..517ac2b 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"آپ کے منتظم نے اپ ڈيٹ کر دیا"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"آپ کے منتظم کی جانب سے حذف کر دیا گیا"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"بیٹری کی میعاد بہتر کرنے میں مدد کرنے کیلئے، بیٹری سیور آپ کے آلہ کی کارکردگی کم کر دیتی ہے اور وائبریشن، مقام کی سروسز اور پس منظر کا بیشتر ڈیٹا محدود کر دیتی ہے۔ ای میل، پیغام رسانی اور مطابقت پذیری پر منحصر دیگر ایپس ممکن ہے اس وقت تک اپ ڈیٹ نہ ہوں جب تک آپ انہیں نہ کھولیں۔\n\nآپ کا آلہ چارج ہوتے وقت بیٹری سیور خود بخود آف ہو جاتی ہے۔"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"مسدود کردہ: یہ اطلاعات کبھی مت دکھائیں"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"پست: اطلاعات کی فہرست کے نیچے خاموشی سے دکھائیں"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"عام: خاموشی سے یہ اطلاعات دکھائیں"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقات"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index c4701b6..667be14 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1440,10 +1440,12 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratoringiz tomonidan o‘chirilgan"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloklangan: bildirishnomalar hech qachon ko‘rsatilmasin"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Past: bildirishnomalar ro‘yxatining pastida ovozsiz ko‘rsatilsin"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Oddiy: bildirishnomalar ovozsiz ko‘rsatilsin"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Yuqori: bildirishnomalar ro‘yxatining yuqorisida ovoz bilan ko‘rsatilsin"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
+    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloklangan: bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
+    <string name="notification_importance_low" msgid="6447640449918427187">"Past: bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
+    <string name="notification_importance_default" msgid="7991157697609575271">"Oddiy: bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+    <string name="notification_importance_high" msgid="3152238637737215654">"Yuqori: bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
     <string name="notification_importance_max" msgid="1153693080467904474">"Shoshilinch: barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d daqiqa (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> gacha)</item>
@@ -1510,4 +1512,8 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta tanlandi</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Boshqa belgilar"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 336f10a..49e14df 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Được cập nhật bởi quản trị viên của bạn"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Đã bị xóa bởi quản trị viên của bạn"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"Mức độ quan trọng"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Đã chặn: Không bao giờ hiển thị các thông báo này"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Thấp: Hiển thị im lặng ở cuối danh sách thông báo"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Bình thường: Hiển thị im lặng các thông báo này"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one">Đã chọn <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Khác"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Bạn đặt tầm quan trọng của các thông báo này."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Thông báo này quan trọng vì những người có liên quan."</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d54eb1e..9492994 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"已被管理员删除"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,节电助手会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n节电助手会在设备充电时自动关闭。"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"屏蔽:一律不显示这些通知"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"低:在通知列表底部显示,不发出提示音"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"一般:显示这些通知,但不发出提示音"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a583e37..0526580 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1440,6 +1440,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"已由您的管理員更新"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"已由管理員刪除"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"節約電池用量模式有助於延長電池壽命,但這會降低裝置效能,並限制震動、定位服務及大部分背景數據傳輸。除非您啟用,否則電郵、短訊及其他需要使用同步功能的應用程式均不會更新。\n\n當裝置充電時,節約電池用量模式會自動關閉。"</string>
+    <string name="notification_importance_title" msgid="7493989722610008700">"重要性"</string>
     <string name="notification_importance_blocked" msgid="7118826900767047125">"已封鎖:永不顯示這些通知"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"低:以靜音方式顯示在通知清單底部"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"一般:以靜音方式顯示這些通知"</string>
@@ -1510,4 +1511,6 @@
       <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"您可以為這些通知設定重要性。"</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及使用者。"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0d360493..8a2d610 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"由您的管理員更新"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"已遭管理員刪除"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"節約耗電量模式會透過降低裝置效能、震動限制、定位服務限制和大多數背景資料運作限制等方式,延長電池續航力。此外,如果未開啟電子郵件、簡訊和其他需要使用同步功能的應用程式,系統將不會自動更新這些應用程式。\n\n當您為裝置充電時,節約耗電量模式會自動關閉。"</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"封鎖:一律不顯示這些通知"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"低:顯示在通知清單底部且不發出任何音效"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"一般:顯示這些通知且不發出任何音效"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ac88851..650ad33 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1440,6 +1440,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ibuyekezwe ngumqondisi wakho"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Isuswe ngumlawuli wakho"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Ukusiza ukuthuthukisa impilo yebhethri, isilondoloze sebhethri sehlisa ukusebenza kwedivayisi yakho futhi sikhawulele ukudlidliza, amasevisi wendawo, nedatha eningi yangasemuva. I-imeyili, imilayezo, nezinye izinhlelo zokusebenza ezincike ekuvumelaniseni zingahle zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri siyavaleka ngokuzenzakalelayo uma idivayisi yakho ishaja."</string>
+    <!-- no translation found for notification_importance_title (7493989722610008700) -->
+    <skip />
     <string name="notification_importance_blocked" msgid="7118826900767047125">"Okuvinjiwe: Ungalokothi ubonise lezi zaziso"</string>
     <string name="notification_importance_low" msgid="6447640449918427187">"Okuphansi: Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
     <string name="notification_importance_default" msgid="7991157697609575271">"Okujwayelekile: Bonisa ngokuthulile lezi zaziso"</string>
@@ -1510,4 +1512,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"Okwahlukahlukene"</string>
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9bca3d6..9f13565 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2791,6 +2791,56 @@
             <flag name="end" value="0x20" />
         </attr>
 
+        <attr name="pointerShape">
+            <!-- Null icon, pointer becomes invisible. -->
+            <enum name="none" value="0" />
+            <!-- The default icon of arrow pointer. -->
+            <enum name="arrow" value="1000" />
+            <!-- Pointer icon indicating context-menu will appear. -->
+            <enum name="context_menu" value="1001" />
+            <!-- Pointer icon of a hand with the index finger. -->
+            <enum name="hand" value="1002" />
+            <!-- Pointer icon indicating help. -->
+            <enum name="help" value="1003" />
+            <!-- Pointer icon indicating something is going on and waiting. -->
+            <enum name="wait" value="1004" />
+            <!-- Pointer icon for cell and grid. -->
+            <enum name="cell" value="1006" />
+            <!-- Pointer icon of crosshair, indicating to spot a location. -->
+            <enum name="crosshair" value="1007" />
+            <!-- Pointer icon of I-beam, usually for text. -->
+            <enum name="text" value="1008" />
+            <!-- Pointer icon of I-beam with 90-degree rotated, for vertical text. -->
+            <enum name="vertical_text" value="1009" />
+            <!-- Pointer icon of 'alias', indicating an alias of/shortcut to something is to be
+                 created. -->
+            <enum name="alias" value="1010" />
+            <!-- Pointer icon of 'copy', used for drag/drop. -->
+            <enum name="copy" value="1011" />
+            <!-- Pointer icon of 'no-drop', indicating the drop will not be accepted at the
+                 current location. -->
+            <enum name="no_drop" value="1012" />
+            <!-- Pointer icon of four-way arrows, indicating scrolling all direction. -->
+            <enum name="all_scroll" value="1013" />
+            <!-- Pointer icon of horizontal double arrow, indicating horizontal resize. -->
+            <enum name="horizontal_double_arrow" value="1014" />
+            <!-- Pointer icon of vertical double arrow, indicating vertical resize. -->
+            <enum name="vertical_double_arrow" value="1015" />
+            <!-- Pointer icon of diagonal double arrow, starting from top-right to bottom-left.
+                 Indicating freeform resize. -->
+            <enum name="top_right_diagonal_double_arrow" value="1016" />
+            <!-- Pointer icon of diagonal double arrow, starting from top-left to bottom-right.
+                 Indicating freeform resize. -->
+            <enum name="top_left_diagonal_double_arrow" value="1017" />
+            <!-- Pointer icon indicating zoom-in. -->
+            <enum name="zoom_in" value="1018" />
+            <!-- Pointer icon indicating zoom-out. -->
+            <enum name="zoom_out" value="1019" />
+            <!-- Pointer icon of a hand sign to grab something. -->
+            <enum name="grab" value="1020" />
+            <!-- Pointer icon of a hand sign while grabbing something. -->
+            <enum name="grabbing" value="1021" />
+        </attr>
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3042,7 +3092,8 @@
         <attr name="imeSubtypeLocale" format="string" />
         <!-- The mode of the subtype. This string can be a mode (e.g. voice, keyboard...) and this
              string will be passed to the IME when the framework calls the IME with the
-             subtype.  -->
+             subtype.  {@link android.view.inputmethod.InputMethodSubtype#getLocale()} returns the
+             value specified in this attribute.  -->
         <attr name="imeSubtypeMode" format="string" />
         <!-- Set true if the subtype is auxiliary.  An auxiliary subtype won't be shown in the
              input method selection list in the settings app.
@@ -3067,6 +3118,9 @@
              this subtype. This is important because many password fields only allow
              ASCII-characters. -->
         <attr name="isAsciiCapable" format="boolean" />
+        <!-- The BCP-47 Language Tag of the subtype.  This replaces
+        {@link android.R.styleable#InputMethod_Subtype_imeSubtypeLocale}.  -->
+        <attr name="languageTag" format="string" />
     </declare-styleable>
 
     <!-- Use <code>spell-checker</code> as the root tag of the XML resource that
@@ -3090,7 +3144,8 @@
         <attr name="label" />
         <!-- The locale of the subtype. This string should be a locale (e.g. en_US, fr_FR...)
              This is also used by the framework to know the supported locales
-             of the spell checker.  -->
+             of the spell checker. {@link android.view.textservice.SpellCheckerSubtype#getLocale()}
+             returns the value specified in this attribute.  -->
         <attr name="subtypeLocale" format="string" />
         <!-- The extra value of the subtype. This string can be any string and will be passed to
              the SpellChecker.  -->
@@ -3102,6 +3157,9 @@
              {@code Arrays.hashCode(new Object[] {subtypeLocale, extraValue}) will be used instead.
               -->
         <attr name="subtypeId" />
+        <!-- The BCP-47 Language Tag of the subtype.  This replaces
+        {@link android.R.styleable#SpellChecker_Subtype_subtypeLocale}.  -->
+        <attr name="languageTag" />
     </declare-styleable>
 
     <!-- Use <code>accessibility-service</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index af8ff2e..7711825 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -130,8 +130,8 @@
     <drawable name="notification_template_divider">#29000000</drawable>
     <drawable name="notification_template_divider_media">#29ffffff</drawable>
 
-    <color name="notification_icon_default_color">#ff616161</color>
-    <color name="notification_action_color_filter">@color/secondary_text_material_light</color>
+    <color name="notification_default_color">#757575</color> <!-- Gray 600 -->
+    <color name="notification_icon_default_color">@color/notification_default_color</color>
 
     <color name="notification_progress_background_color">@color/secondary_text_material_light</color>
 
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 7399fa9..dd18544 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -48,6 +48,8 @@
     <color name="primary_text_default_material_light">#de000000</color>
     <!-- 54% black -->
     <color name="secondary_text_default_material_light">#8a000000</color>
+    <!-- 38% black -->
+    <color name="tertiary_text_default_material_light">#61000000</color>
 
     <!-- 100% white -->
     <color name="primary_text_default_material_dark">#ffffffff</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 97c0e07..bff8b1a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1018,6 +1018,10 @@
     <!-- Light sensor event rate in milliseconds for automatic brightness control. -->
     <integer name="config_autoBrightnessLightSensorRate">250</integer>
 
+    <!-- The maximum range of gamma adjustment possible using the screen
+         auto-brightness adjustment setting. -->
+    <fraction name="config_autoBrightnessAdjustmentMaxGamma">300%</fraction>
+
     <!-- If we allow automatic adjustment of screen brightness while dozing, how many times we want
          to reduce it to preserve the battery. Value of 100% means no scaling. -->
     <fraction name="config_screenAutoBrightnessDozeScaleFactor">100%</fraction>
@@ -1035,6 +1039,9 @@
          adapt to the environment.  This mode may be better suited for watches. -->
     <bool name="config_autoBrightnessResetAmbientLuxAfterWarmUp">true</bool>
 
+    <!-- Period of time in which to consider light samples in milliseconds. -->
+    <integer name="config_autoBrightnessAmbientLightHorizon">10000</integer>
+
     <!-- Screen brightness used to dim the screen when the user activity
          timeout expires.  May be less than the minimum allowed brightness setting
          that can be set by the user. -->
@@ -2154,11 +2161,6 @@
         string that's stored in 8-bit unpacked format) characters.-->
     <bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
 
-    <!-- List of package names (ordered by preference) providing WebView implementations. -->
-    <string-array name="config_webViewPackageNames" translatable="false">
-      <item>com.android.webview</item>
-    </string-array>
-
     <!-- If EMS is not supported, framework breaks down EMS into single segment SMS
          and adds page info " x/y". This config is used to set which carrier doesn't
          support EMS and whether page info should be added at the beginning or the end.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b6b2e20..ad36f3c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2683,6 +2683,8 @@
     <public type="attr" name="encryptionAware" />
     <public type="attr" name="preferenceFragmentStyle" />
     <public type="attr" name="canControlMagnification" />
+    <public type="attr" name="languageTag" />
+    <public type="attr" name="pointerShape" />
 
     <public type="style" name="Theme.Material.DayNight" />
     <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e5415df..4d967ff 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3955,6 +3955,9 @@
     <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
 
 
+    <!-- [CHAR LIMIT=100] Notification importance slider title -->
+    <string name="notification_importance_title">Importance</string>
+
     <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
     <string name="notification_importance_blocked">Blocked: Never show these notifications</string>
 
@@ -4102,4 +4105,7 @@
     </plurals>
 
     <string name="default_notification_topic_label">Miscellaneous</string>
+
+    <string name="importance_from_topic">You set the importance of these notifications.</string>
+    <string name="importance_from_person">This is important because of the people involved.</string>
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index adcb79b..74ebf26 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -442,12 +442,11 @@
     </style>
 
     <style name="TextAppearance.Material.Notification.Info">
+        <item name="textColor">@color/tertiary_text_default_material_light</item>
         <item name="textSize">@dimen/notification_subtext_size</item>
     </style>
 
-    <style name="TextAppearance.Material.Notification.Time">
-        <item name="textSize">@dimen/notification_subtext_size</item>
-    </style>
+    <style name="TextAppearance.Material.Notification.Time" parent="TextAppearance.Material.Notification.Info" />
 
     <style name="TextAppearance.Material.Notification.Emphasis">
         <item name="textColor">#66000000</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eadcae0..36ba306 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -16,10 +16,6 @@
 */
 -->
 <resources>
-  <!-- We don't want to publish private symbols in android.R as part of the
-       SDK.  Instead, put them here. -->
-  <private-symbols package="com.android.internal" />
-
   <!-- Private symbols that we need to reference from framework code.  See
        frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate
        this.
@@ -1697,6 +1693,8 @@
   <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
   <java-symbol type="fraction" name="config_displayFractionForDefaultMinimalSizeOfResizeableTask" />
   <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
+  <java-symbol type="fraction" name="config_autoBrightnessAdjustmentMaxGamma" />
+  <java-symbol type="integer" name="config_autoBrightnessAmbientLightHorizon"/>
   <java-symbol type="integer" name="config_autoBrightnessBrighteningLightDebounce"/>
   <java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
   <java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/>
@@ -1878,7 +1876,6 @@
   <java-symbol type="layout" name="notification_template_material_big_text" />
   <java-symbol type="layout" name="notification_template_header" />
   <java-symbol type="layout" name="notification_material_media_action" />
-  <java-symbol type="color" name="notification_action_color_filter" />
   <java-symbol type="color" name="notification_icon_default_color" />
   <java-symbol type="color" name="notification_progress_background_color" />
   <java-symbol type="id" name="media_actions" />
@@ -1958,9 +1955,12 @@
   <java-symbol type="bool" name="config_built_in_sip_phone" />
   <java-symbol type="id" name="maximize_window" />
   <java-symbol type="id" name="close_window" />
-  <java-symbol type="layout" name="decor_caption_light" />
-  <java-symbol type="layout" name="decor_caption_dark" />
+  <java-symbol type="layout" name="decor_caption" />
   <java-symbol type="drawable" name="decor_caption_title_focused" />
+  <java-symbol type="drawable" name="decor_close_button_dark" />
+  <java-symbol type="drawable" name="decor_close_button_light" />
+  <java-symbol type="drawable" name="decor_maximize_button_dark" />
+  <java-symbol type="drawable" name="decor_maximize_button_light" />
 
   <!-- From TelephonyProvider -->
   <java-symbol type="xml" name="apns" />
@@ -2020,7 +2020,7 @@
   <java-symbol type="attr" name="actionModeWebSearchDrawable" />
   <java-symbol type="string" name="websearch" />
   <java-symbol type="drawable" name="ic_media_video_poster" />
-  <java-symbol type="array" name="config_webViewPackageNames" />
+  <java-symbol type="xml" name="config_webview_packages" />
 
   <!-- From SubtitleView -->
   <java-symbol type="dimen" name="subtitle_corner_radius" />
@@ -2090,6 +2090,7 @@
   <java-symbol type="string" name="notification_importance_default" />
   <java-symbol type="string" name="notification_importance_high" />
   <java-symbol type="string" name="notification_importance_max" />
+  <java-symbol type="string" name="notification_importance_title" />
 
   <java-symbol type="string" name="select_day" />
   <java-symbol type="string" name="select_year" />
@@ -2267,6 +2268,7 @@
 
   <!-- Floating toolbar -->
   <java-symbol type="id" name="floating_toolbar_menu_item_image_button" />
+  <java-symbol type="id" name="overflow" />
   <java-symbol type="layout" name="floating_popup_container" />
   <java-symbol type="layout" name="floating_popup_menu_button" />
   <java-symbol type="layout" name="floating_popup_open_overflow_button" />
@@ -2380,4 +2382,6 @@
   <java-symbol type="dimen" name="notification_content_margin_end" />
   <java-symbol type="dimen" name="notification_content_picture_margin" />
   <java-symbol type="dimen" name="notification_content_margin_top" />
+  <java-symbol type="string" name="importance_from_topic" />
+  <java-symbol type="string" name="importance_from_person" />
 </resources>
diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
new file mode 100644
index 0000000..6f9c58d
--- /dev/null
+++ b/core/res/res/xml/config_webview_packages.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<webviewproviders>
+    <!-- The default WebView implementation -->
+    <webviewprovider description="Android WebView" packageName="com.android.webview" />
+</webviewproviders>
diff --git a/core/tests/coretests/res/layout/activity_text_view.xml b/core/tests/coretests/res/layout/activity_text_view.xml
index 7ab0b13..e795c10 100644
--- a/core/tests/coretests/res/layout/activity_text_view.xml
+++ b/core/tests/coretests/res/layout/activity_text_view.xml
@@ -23,6 +23,6 @@
     <EditText
             android:id="@+id/textview"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="wrap_content" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
index 73fdb10..4a1c414 100644
--- a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
@@ -30,11 +30,16 @@
  */
 public class SpellCheckerSubtypeTest extends InstrumentationTestCase {
     private static final int SUBTYPE_SUBTYPE_ID_NONE = 0;
+    private static final String SUBTYPE_SUBTYPE_LOCALE_STRING_NONE = "";
+    private static final String SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE = "";
+
     private static final String SUBTYPE_SUBTYPE_LOCALE_STRING_A = "en_GB";
+    private static final String SUBTYPE_SUBTYPE_LANGUAGE_TAG_A = "en-GB";
     private static final int SUBTYPE_NAME_RES_ID_A = 0x12345;
     private static final String SUBTYPE_EXTRA_VALUE_A = "Key1=Value1,Key2=Value2";
     private static final int SUBTYPE_SUBTYPE_ID_A = 42;
     private static final String SUBTYPE_SUBTYPE_LOCALE_STRING_B = "en_IN";
+    private static final String SUBTYPE_SUBTYPE_LANGUAGE_TAG_B = "en-IN";
     private static final int SUBTYPE_NAME_RES_ID_B = 0x54321;
     private static final String SUBTYPE_EXTRA_VALUE_B = "Key3=Value3,Key4=Value4";
     private static final int SUBTYPE_SUBTYPE_ID_B = -42;
@@ -60,9 +65,11 @@
     @SmallTest
     public void testSubtypeWithNoSubtypeId() throws Exception {
         final SpellCheckerSubtype subtype = new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A,
-                SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE);
+                SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_SUBTYPE_LANGUAGE_TAG_A,
+                SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE);
         assertEquals(SUBTYPE_NAME_RES_ID_A, subtype.getNameResId());
         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, subtype.getLocale());
+        assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, subtype.getLanguageTag());
         assertEquals("Value1", subtype.getExtraValueOf("Key1"));
         assertEquals("Value2", subtype.getExtraValueOf("Key2"));
         // Historically we have used SpellCheckerSubtype#hashCode() to track which subtype is
@@ -75,6 +82,7 @@
         final SpellCheckerSubtype clonedSubtype = cloneViaParcel(subtype);
         assertEquals(SUBTYPE_NAME_RES_ID_A, clonedSubtype.getNameResId());
         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, clonedSubtype.getLocale());
+        assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, clonedSubtype.getLanguageTag());
         assertEquals("Value1", clonedSubtype.getExtraValueOf("Key1"));
         assertEquals("Value2", clonedSubtype.getExtraValueOf("Key2"));
         assertEquals(
@@ -84,10 +92,12 @@
 
     public void testSubtypeWithSubtypeId() throws Exception {
         final SpellCheckerSubtype subtype = new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A,
-                SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A);
+                SUBTYPE_SUBTYPE_LOCALE_STRING_A, SUBTYPE_SUBTYPE_LANGUAGE_TAG_A,
+                SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A);
 
         assertEquals(SUBTYPE_NAME_RES_ID_A, subtype.getNameResId());
         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, subtype.getLocale());
+        assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, subtype.getLanguageTag());
         assertEquals("Value1", subtype.getExtraValueOf("Key1"));
         assertEquals("Value2", subtype.getExtraValueOf("Key2"));
         // Similar to "SubtypeId" in InputMethodSubtype, "SubtypeId" in SpellCheckerSubtype enables
@@ -97,6 +107,7 @@
         final SpellCheckerSubtype clonedSubtype = cloneViaParcel(subtype);
         assertEquals(SUBTYPE_NAME_RES_ID_A, clonedSubtype.getNameResId());
         assertEquals(SUBTYPE_SUBTYPE_LOCALE_STRING_A, clonedSubtype.getLocale());
+        assertEquals(SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, clonedSubtype.getLanguageTag());
         assertEquals("Value1", clonedSubtype.getExtraValueOf("Key1"));
         assertEquals("Value2", clonedSubtype.getExtraValueOf("Key2"));
         assertEquals(SUBTYPE_SUBTYPE_ID_A, clonedSubtype.hashCode());
@@ -104,30 +115,42 @@
 
     @SmallTest
     public void testGetLocaleObject() throws Exception {
-        assertEquals(new Locale("en"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "en", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
-        assertEquals(new Locale("en", "US"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "en_US", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
-        assertEquals(new Locale("en", "US", "POSIX"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "en_US_POSIX", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
+        assertEquals(new Locale("en", "GB"),
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, "en_GB",
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
+        assertEquals(new Locale("en", "GB"),
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_NONE,
+                        "en-GB", SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
 
-        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
-        // support three letter language codes, and used "tl" (Tagalog) as the language string for
-        // "fil" (Filipino).
-        assertEquals(new Locale("fil"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "tl", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
-        assertEquals(new Locale("fil", "PH"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "tl_PH", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
-        assertEquals(new Locale("fil", "PH", "POSIX"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "tl_PH_POSIX", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
+        // If neither locale string nor language tag is specified,
+        // {@link SpellCheckerSubtype#getLocaleObject} returns null.
+        assertNull(
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_NONE,
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
 
-        // So far rejecting invalid/unexpected locale strings is out of the scope.
-        assertEquals(new Locale("a"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "a", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
-        assertEquals(new Locale("a b c"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "a b c", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
-        assertEquals(new Locale("en-US"), new SpellCheckerSubtype(
-                SUBTYPE_NAME_RES_ID_A, "en-US", SUBTYPE_EXTRA_VALUE_A).getLocaleObject());
+        // If both locale string and language tag are specified,
+        // {@link SpellCheckerSubtype#getLocaleObject} uses language tag.
+        assertEquals(new Locale("en", "GB"),
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, "en_US", "en-GB",
+                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
+
+        // Make sure that "tl_PH" is rewritten to "fil_PH" for spell checkers that need to support
+        // Android KitKat and prior, which do not support 3-letter language codes.
+        assertEquals(new Locale("fil", "PH"),
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, "tl_PH",
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_NONE, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE).getLocaleObject());
+
+        // "languageTag" attribute is available in Android N and later, where 3-letter country codes
+        // are guaranteed to be available.  It's developers' responsibility for specifying a valid
+        // country subtags here and we do not rewrite "tl" to "fil" for simplicity.
+        assertEquals("tl",
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_NONE,
+                        "tl-PH", SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE)
+                        .getLocaleObject().getLanguage());
     }
 
     @SmallTest
@@ -156,50 +179,83 @@
         // If subtype ID is 0 (== SUBTYPE_SUBTYPE_ID_NONE), we keep the same behavior.
         assertEquals(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE));
         assertNotEqual(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_B, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE));
         assertNotEqual(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE));
         assertNotEqual(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_NONE),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_B, SUBTYPE_SUBTYPE_ID_NONE));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_B, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE));
+        assertNotEqual(
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_NONE),
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_B,
+                        SUBTYPE_SUBTYPE_ID_NONE));
 
         // If subtype ID is not 0, we test the equality based only on the subtype ID.
         assertEquals(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A));
         assertEquals(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_B, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A));
         assertEquals(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_B,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A));
         assertEquals(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_B, SUBTYPE_SUBTYPE_ID_A));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_B, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A));
+        assertEquals(
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A),
+                new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_B,
+                        SUBTYPE_SUBTYPE_ID_A));
         assertNotEqual(
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_A),
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_A),
                 new SpellCheckerSubtype(SUBTYPE_NAME_RES_ID_A, SUBTYPE_SUBTYPE_LOCALE_STRING_A,
-                        SUBTYPE_EXTRA_VALUE_A, SUBTYPE_SUBTYPE_ID_B));
+                        SUBTYPE_SUBTYPE_LANGUAGE_TAG_A, SUBTYPE_EXTRA_VALUE_A,
+                        SUBTYPE_SUBTYPE_ID_B));
     }
+
 }
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index ddbdc87..83a9e01 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -16,15 +16,23 @@
 
 package android.widget;
 
+import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
+import static android.widget.espresso.DragHandleUtils.onHandleView;
+import static android.widget.espresso.TextViewActions.mouseClickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.mouseDoubleClickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.mouseLongClickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.mouseDoubleClickAndDragOnText;
 import static android.widget.espresso.TextViewActions.mouseDragOnText;
 import static android.widget.espresso.TextViewActions.mouseLongClickAndDragOnText;
+import static android.widget.espresso.TextViewActions.mouseTripleClickAndDragOnText;
+import static android.widget.espresso.TextViewActions.mouseTripleClickOnTextAtIndex;
 import static android.widget.espresso.TextViewAssertions.hasSelection;
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.action.ViewActions.replaceText;
 import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
 
 import com.android.frameworks.coretests.R;
@@ -48,10 +56,23 @@
         final String helloWorld = "Hello world!";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+
+        assertNoSelectionHandles();
+
         onView(withId(R.id.textview)).perform(
                 mouseDragOnText(helloWorld.indexOf("llo"), helloWorld.indexOf("ld!")));
 
         onView(withId(R.id.textview)).check(hasSelection("llo wor"));
+
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .check(matches(isDisplayed()));
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .check(matches(isDisplayed()));
+
+        onView(withId(R.id.textview)).perform(mouseClickOnTextAtIndex(helloWorld.indexOf("w")));
+        onView(withId(R.id.textview)).check(hasSelection(""));
+
+        assertNoSelectionHandles();
     }
 
     @SmallTest
@@ -89,6 +110,9 @@
         onView(withId(R.id.textview)).perform(mouseLongClickOnTextAtIndex(
                 helloWorld.indexOf("rld")));
         onView(withId(R.id.textview)).check(hasSelection("world"));
+
+        onView(withId(R.id.textview)).perform(mouseLongClickOnTextAtIndex(helloWorld.length()));
+        onView(withId(R.id.textview)).check(hasSelection("!"));
     }
 
     @SmallTest
@@ -113,6 +137,9 @@
         onView(withId(R.id.textview)).perform(mouseDoubleClickOnTextAtIndex(
                 helloWorld.indexOf("rld")));
         onView(withId(R.id.textview)).check(hasSelection("world"));
+
+        onView(withId(R.id.textview)).perform(mouseDoubleClickOnTextAtIndex(helloWorld.length()));
+        onView(withId(R.id.textview)).check(hasSelection("!"));
     }
 
     @SmallTest
@@ -166,4 +193,102 @@
                 mouseLongClickAndDragOnText(text.indexOf("j"), text.indexOf("f")));
         onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
     }
+
+    @SmallTest
+    public void testSelectTextByTripleClick() throws Exception {
+        getActivity();
+
+        final StringBuilder builder = new StringBuilder();
+        builder.append("First paragraph.\n");
+        builder.append("Second paragraph.");
+        for (int i = 0; i < 10; i++) {
+            builder.append(" This paragraph is very long.");
+        }
+        builder.append('\n');
+        builder.append("Third paragraph.");
+        final String text = builder.toString();
+
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickOnTextAtIndex(text.indexOf("rst")));
+        onView(withId(R.id.textview)).check(hasSelection("First paragraph.\n"));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickOnTextAtIndex(text.indexOf("cond")));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf("Second"), text.indexOf("Third"))));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickOnTextAtIndex(text.indexOf("ird")));
+        onView(withId(R.id.textview)).check(hasSelection("Third paragraph."));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickOnTextAtIndex(text.indexOf("very long")));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf("Second"), text.indexOf("Third"))));
+    }
+
+    @SmallTest
+    public void testSelectTextByTripleClickAndDrag() throws Exception {
+        getActivity();
+
+        final StringBuilder builder = new StringBuilder();
+        builder.append("First paragraph.\n");
+        builder.append("Second paragraph.");
+        for (int i = 0; i < 10; i++) {
+            builder.append(" This paragraph is very long.");
+        }
+        builder.append('\n');
+        builder.append("Third paragraph.");
+        final String text = builder.toString();
+
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickAndDragOnText(text.indexOf("irst"), text.indexOf("st")));
+        onView(withId(R.id.textview)).check(hasSelection("First paragraph.\n"));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickAndDragOnText(text.indexOf("cond"), text.indexOf("Third") - 2));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf("Second"), text.indexOf("Third"))));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickAndDragOnText(text.indexOf("First"), text.indexOf("ird")));
+        onView(withId(R.id.textview)).check(hasSelection(text));
+    }
+
+    @SmallTest
+    public void testSelectTextByTripleClickAndDrag_reverse() throws Exception {
+        getActivity();
+
+        final StringBuilder builder = new StringBuilder();
+        builder.append("First paragraph.\n");
+        builder.append("Second paragraph.");
+        for (int i = 0; i < 10; i++) {
+            builder.append(" This paragraph is very long.");
+        }
+        builder.append('\n');
+        builder.append("Third paragraph.");
+        final String text = builder.toString();
+
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickAndDragOnText(text.indexOf("st"), text.indexOf("irst")));
+        onView(withId(R.id.textview)).check(hasSelection("First paragraph.\n"));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickAndDragOnText(text.indexOf("Third") - 2, text.indexOf("cond")));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf("Second"), text.indexOf("Third"))));
+
+        onView(withId(R.id.textview)).perform(
+                mouseTripleClickAndDragOnText(text.indexOf("ird"), text.indexOf("First")));
+        onView(withId(R.id.textview)).check(hasSelection(text));
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 4614505..e54723e 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles;
+import static android.widget.espresso.DragHandleUtils.onHandleView;
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
 import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
@@ -26,24 +28,22 @@
 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
 import static android.widget.espresso.TextViewAssertions.hasSelection;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.action.ViewActions.pressKey;
+import static android.support.test.espresso.action.ViewActions.replaceText;
 import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.hamcrest.Matchers.allOf;
 
 import com.android.frameworks.coretests.R;
 
-import android.support.test.espresso.NoMatchingRootException;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewInteraction;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.KeyEvent;
@@ -153,19 +153,115 @@
 
     @SmallTest
     public void testToolbarAppearsAfterSelection() throws Exception {
-        // It'll be nice to check that the toolbar is not visible (or does not exist) here
-        // I can't currently find a way to do this. I'll get to it later.
-
         final String text = "Toolbar appears after selection.";
         onView(withId(R.id.textview)).perform(click());
+        assertFloatingToolbarIsNotDisplayed();
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
         onView(withId(R.id.textview)).perform(
                 longPressOnTextAtIndex(text.indexOf("appears")));
 
-        // It takes the toolbar less than 100ms to start to animate into screen.
-        // Ideally, we'll wait using the UiController, but I guess this works for now.
-        Thread.sleep(100);
-        assertFloatingToolbarIsDisplayed(getActivity());
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        final String text2 = "Toolbar disappears after typing text.";
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2));
+        assertFloatingToolbarIsNotDisplayed();
+    }
+
+    @SmallTest
+    public void testToolbarAndInsertionHandle() throws Exception {
+        final String text = "text";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+        assertFloatingToolbarIsNotDisplayed();
+
+        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.selectAll));
+        assertFloatingToolbarDoesNotContainItem(
+                getActivity().getString(com.android.internal.R.string.copy));
+        assertFloatingToolbarDoesNotContainItem(
+                getActivity().getString(com.android.internal.R.string.cut));
+    }
+
+    @SmallTest
+    public void testToolbarAndSelectionHandle() throws Exception {
+        final String text = "abcd efg hijk";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.selectAll));
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.copy));
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.cut));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        assertFloatingToolbarDoesNotContainItem(
+                getActivity().getString(com.android.internal.R.string.selectAll));
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.copy));
+        assertFloatingToolbarContainsItem(
+                getActivity().getString(com.android.internal.R.string.cut));
+    }
+
+    @SmallTest
+    public void testInsertionHandle() throws Exception {
+        final String text = "abcd efg hijk ";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+
+        onHandleView(com.android.internal.R.id.insertion_handle)
+                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
+
+        onHandleView(com.android.internal.R.id.insertion_handle)
+                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
+    }
+
+    @SmallTest
+    public void testInsertionHandle_multiLine() throws Exception {
+        final String text = "abcd\n" + "efg\n" + "hijk\n";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
+
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+
+        onHandleView(com.android.internal.R.id.insertion_handle)
+                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
+
+        onHandleView(com.android.internal.R.id.insertion_handle)
+                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
     }
 
     @SmallTest
@@ -183,7 +279,7 @@
         onHandleView(com.android.internal.R.id.selection_end_handle)
                 .check(matches(isDisplayed()));
 
-        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
         onView(withId(R.id.textview)).check(hasSelection("abcd efg"));
@@ -200,7 +296,7 @@
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
         onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
 
-        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('e')));
         onView(withId(R.id.textview)).check(hasSelection("efg\nhijk"));
@@ -219,13 +315,46 @@
     }
 
     @SmallTest
+    public void testSelectionHandles_multiLine_rtl() throws Exception {
+        // Arabic text.
+        final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
+                + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
+                + "\u0639\u063A\u063B";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
+        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0634')));
+
+        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062E')));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf('\u062D'), text.indexOf('\u0635') + 1)));
+
+        onHandleView(com.android.internal.R.id.selection_start_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062A')));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf('\u062A'), text.indexOf('\u0635') + 1)));
+
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u0638')));
+        onView(withId(R.id.textview)).check(hasSelection(
+                text.substring(text.indexOf('\u062A'), text.indexOf('\u0638') + 1)));
+
+        onHandleView(com.android.internal.R.id.selection_end_handle)
+                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u063B')));
+        onView(withId(R.id.textview)).check(hasSelection(text));
+    }
+
+
+    @SmallTest
     public void testSelectionHandles_doesNotPassAnotherHandle() throws Exception {
         final String text = "abcd efg hijk lmn";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
         onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
 
-        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
         onView(withId(R.id.textview)).check(hasSelection("g"));
@@ -243,7 +372,7 @@
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
         onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
 
-        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
         onView(withId(R.id.textview)).check(hasSelection("k"));
@@ -261,7 +390,7 @@
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
         onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
 
-        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
 
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
@@ -314,7 +443,7 @@
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
         onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('m')));
 
-        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
+        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
 
         onHandleView(com.android.internal.R.id.selection_start_handle)
                 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
@@ -342,25 +471,4 @@
                 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
         onView(withId(R.id.textview)).check(hasSelection("hijk"));
     }
-
-    private static void assertNoSelectionHandles() {
-        try {
-            onHandleView(com.android.internal.R.id.selection_start_handle)
-                    .check(matches(isDisplayed()));
-        } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
-            try {
-                onHandleView(com.android.internal.R.id.selection_end_handle)
-                        .check(matches(isDisplayed()));
-            } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e1) {
-                return;
-            }
-        }
-        throw new AssertionError("Selection handle found");
-    }
-
-    private static ViewInteraction onHandleView(int id)
-            throws NoMatchingRootException, NoMatchingViewException, AssertionError {
-        return onView(allOf(withId(id), isAssignableFrom(Editor.HandleView.class)))
-                .inRoot(withDecorView(hasDescendant(withId(id))));
-    }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/DragAction.java b/core/tests/coretests/src/android/widget/espresso/DragAction.java
index ce97568..b2c8e38 100644
--- a/core/tests/coretests/src/android/widget/espresso/DragAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/DragAction.java
@@ -157,6 +157,59 @@
         },
 
         /**
+         * Starts a drag with a mouse triple click.
+         */
+        MOUSE_TRIPLE_CLICK {
+            private DownMotionPerformer downMotion = new DownMotionPerformer() {
+                @Override
+                @Nullable
+                public MotionEvent perform(
+                        UiController uiController, float[] coordinates, float[] precision) {
+                    MotionEvent downEvent = MotionEvents.sendDown(
+                            uiController, coordinates, precision)
+                            .down;
+                    for (int i = 0; i < 2; ++i) {
+                        try {
+                            if (!MotionEvents.sendUp(uiController, downEvent)) {
+                                String logMessage = "Injection of up event as part of the triple "
+                                        + "click failed. Sending cancel event.";
+                                Log.d(TAG, logMessage);
+                                MotionEvents.sendCancel(uiController, downEvent);
+                                return null;
+                            }
+
+                            long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
+                            uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
+                        } finally {
+                            downEvent.recycle();
+                        }
+                        downEvent = MotionEvents.sendDown(
+                                uiController, coordinates, precision).down;
+                    }
+                    return downEvent;
+                }
+            };
+
+            @Override
+            public Status sendSwipe(
+                    UiController uiController,
+                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
+                return sendLinearDrag(
+                        uiController, downMotion, startCoordinates, endCoordinates, precision);
+            }
+
+            @Override
+            public String toString() {
+                return "mouse triple click and drag to select";
+            }
+
+            @Override
+            public UiController wrapUiController(UiController uiController) {
+                return new MouseUiController(uiController);
+            }
+        },
+
+        /**
          * Starts a drag with a tap.
          */
         TAP {
diff --git a/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java b/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
new file mode 100644
index 0000000..f744cae
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/DragHandleUtils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.hamcrest.Matchers.allOf;
+
+import android.support.test.espresso.NoMatchingRootException;
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewInteraction;
+import android.widget.Editor;
+
+public class DragHandleUtils {
+    private DragHandleUtils() {
+
+    }
+
+    public static void assertNoSelectionHandles() {
+        try {
+            onHandleView(com.android.internal.R.id.selection_start_handle)
+                    .check(matches(isDisplayed()));
+        } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+            try {
+                onHandleView(com.android.internal.R.id.selection_end_handle)
+                        .check(matches(isDisplayed()));
+            } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e1) {
+                return;
+            }
+        }
+        throw new AssertionError("Selection handle found");
+    }
+
+    public static ViewInteraction onHandleView(int id)
+            throws NoMatchingRootException, NoMatchingViewException, AssertionError {
+        return onView(allOf(withId(id), isAssignableFrom(Editor.HandleView.class)))
+                .inRoot(withDecorView(hasDescendant(withId(id))));
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index fc01d84..f02fe00 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -19,31 +19,133 @@
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
 import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
 
-import android.app.Activity;
+import org.hamcrest.Matcher;
+
+import android.support.test.espresso.NoMatchingRootException;
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.ViewInteraction;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.espresso.matcher.ViewMatchers;
+import android.view.View;
+
 import com.android.internal.widget.FloatingToolbar;
 
 /**
  * Espresso utility methods for the floating toolbar.
  */
 public class FloatingToolbarEspressoUtils {
-
+    private final static Object TAG = FloatingToolbar.FLOATING_TOOLBAR_TAG;
 
     private FloatingToolbarEspressoUtils() {}
 
+    private static ViewInteraction onFloatingToolBar() {
+        return onView(withTagValue(is(TAG)))
+                .inRoot(withDecorView(hasDescendant(withTagValue(is(TAG)))));
+    }
+
     /**
      * Asserts that the floating toolbar is displayed on screen.
      *
      * @throws AssertionError if the assertion fails
      */
-    public static void assertFloatingToolbarIsDisplayed(Activity activity) {
-        onView(withTagValue(is((Object) FloatingToolbar.FLOATING_TOOLBAR_TAG)))
-                .inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))))
-                .check(matches(isDisplayed()));
+    public static void assertFloatingToolbarIsDisplayed() {
+        onFloatingToolBar().check(matches(isDisplayed()));
     }
 
+    /**
+     * Asserts that the floating toolbar is not displayed on screen.
+     *
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertFloatingToolbarIsNotDisplayed() {
+        try {
+            onFloatingToolBar().check(matches(isDisplayed()));
+        } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+            return;
+        }
+        throw new AssertionError("Floating toolbar is displayed");
+    }
+
+    private static void toggleOverflow() {
+        final int id = com.android.internal.R.id.overflow;
+        onView(allOf(withId(id), isDisplayed()))
+                .inRoot(withDecorView(hasDescendant(withId(id))))
+                .perform(ViewActions.click());
+        onView(isRoot()).perform(SLEEP);
+    }
+
+    public static void sleepForFloatingToolbarPopup() {
+        onView(isRoot()).perform(SLEEP);
+    }
+
+    /**
+     * Asserts that the floating toolbar contains the specified item.
+     *
+     * @param itemLabel label of the item.
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertFloatingToolbarContainsItem(String itemLabel) {
+        try{
+            onFloatingToolBar().check(matches(hasDescendant(ViewMatchers.withText(itemLabel))));
+        } catch (AssertionError e) {
+            try{
+                toggleOverflow();
+            } catch (NoMatchingViewException | NoMatchingRootException e2) {
+                // No overflow items.
+                throw e;
+            }
+            try{
+                onFloatingToolBar().check(matches(hasDescendant(ViewMatchers.withText(itemLabel))));
+            } finally {
+                toggleOverflow();
+            }
+        }
+    }
+
+    /**
+     * Asserts that the floating toolbar doesn't contain the specified item.
+     *
+     * @param itemLabel label of the item.
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
+        try{
+            assertFloatingToolbarContainsItem(itemLabel);
+        } catch (AssertionError e) {
+            return;
+        }
+        throw new AssertionError("Floating toolbar contains " + itemLabel);
+    }
+
+    /**
+     * ViewAction to sleep to wait floating toolbar's animation.
+     */
+    private static final ViewAction SLEEP = new ViewAction() {
+        private static final long SLEEP_DURATION = 400;
+
+        @Override
+        public Matcher<View> getConstraints() {
+            return isDisplayed();
+        }
+
+        @Override
+        public String getDescription() {
+            return "Sleep " + SLEEP_DURATION + " ms.";
+        }
+
+        @Override
+        public void perform(UiController uiController, View view) {
+            uiController.loopMainThreadForAtLeast(SLEEP_DURATION);
+        }
+    };
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index de640ca..e51f2785 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -22,9 +22,13 @@
 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.PrecisionDescriber;
+import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Tapper;
 import android.view.View;
+import android.view.ViewConfiguration;
 
 /**
  * ViewAction for performing an click on View by a mouse.
@@ -32,10 +36,58 @@
 public final class MouseClickAction implements ViewAction {
     private final GeneralClickAction mGeneralClickAction;
 
-    public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
-            PrecisionDescriber precisionDescriber) {
+    public enum CLICK implements Tapper {
+        TRIPLE {
+            @Override
+            public Tapper.Status sendTap(UiController uiController, float[] coordinates,
+                    float[] precision) {
+                Tapper.Status stat = sendSingleTap(uiController, coordinates, precision);
+                boolean warning = false;
+                if (stat == Tapper.Status.FAILURE) {
+                    return Tapper.Status.FAILURE;
+                } else if (stat == Tapper.Status.WARNING) {
+                    warning = true;
+                }
+
+                long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
+                for (int i = 0; i < 2; i++) {
+                    if (0 < doubleTapMinimumTimeout) {
+                        uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
+                    }
+                    stat = sendSingleTap(uiController, coordinates, precision);
+                    if (stat == Tapper.Status.FAILURE) {
+                        return Tapper.Status.FAILURE;
+                    } else if (stat == Tapper.Status.WARNING) {
+                        warning = true;
+                    }
+                }
+
+                if (warning) {
+                    return Tapper.Status.WARNING;
+                } else {
+                    return Tapper.Status.SUCCESS;
+                }
+            }
+        };
+
+        private static Tapper.Status sendSingleTap(UiController uiController,
+                float[] coordinates, float[] precision) {
+            DownResultHolder res = MotionEvents.sendDown(uiController, coordinates, precision);
+            try {
+                if (!MotionEvents.sendUp(uiController, res.down)) {
+                    MotionEvents.sendCancel(uiController, res.down);
+                    return Tapper.Status.FAILURE;
+                }
+            } finally {
+                res.down.recycle();
+            }
+            return res.longPress ? Tapper.Status.WARNING : Tapper.Status.SUCCESS;
+        }
+    };
+
+    public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider) {
         mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
-                precisionDescriber);
+                Press.PINPOINT);
     }
 
     @Override
@@ -51,5 +103,13 @@
     @Override
     public void perform(UiController uiController, View view) {
         mGeneralClickAction.perform(new MouseUiController(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 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);
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 32cc6d6..54d5823 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -64,7 +64,7 @@
      */
     public static ViewAction mouseClickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index), Press.PINPOINT));
+                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index)));
     }
 
     /**
@@ -94,7 +94,7 @@
      */
     public static ViewAction mouseDoubleClickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new MouseClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.PINPOINT));
+                new MouseClickAction(Tap.DOUBLE, new TextCoordinates(index)));
     }
 
     /**
@@ -124,7 +124,22 @@
      */
     public static ViewAction mouseLongClickOnTextAtIndex(int index) {
         return actionWithAssertions(
-                new MouseClickAction(Tap.LONG, new TextCoordinates(index), Press.PINPOINT));
+                new MouseClickAction(Tap.LONG, new TextCoordinates(index)));
+    }
+
+    /**
+     * Returns an action that triple-clicks by mouse on text at an index on the TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param index The index of the TextView's text to triple-click on.
+     */
+    public static ViewAction mouseTripleClickOnTextAtIndex(int index) {
+        return actionWithAssertions(
+                new MouseClickAction(MouseClickAction.CLICK.TRIPLE, new TextCoordinates(index)));
     }
 
     /**
@@ -237,6 +252,28 @@
                         TextView.class));
     }
 
+    /**
+    * Returns an action that triple click then drags by mouse on text from startIndex to endIndex
+    * on the TextView.<br>
+    * <br>
+    * View constraints:
+    * <ul>
+    * <li>must be a TextView displayed on screen
+    * <ul>
+    *
+    * @param startIndex The index of the TextView's text to start a drag from
+    * @param endIndex The index of the TextView's text to end the drag at
+    */
+   public static ViewAction mouseTripleClickAndDragOnText(int startIndex, int endIndex) {
+       return actionWithAssertions(
+               new DragAction(
+                       DragAction.Drag.MOUSE_TRIPLE_CLICK,
+                       new TextCoordinates(startIndex),
+                       new TextCoordinates(endIndex),
+                       Press.PINPOINT,
+                       TextView.class));
+   }
+
     public enum Handle {
         SELECTION_START,
         SELECTION_END,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 51019cc..b4f88c33 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -106,6 +106,7 @@
     </permission>
 
     <permission name="android.permission.ACCESS_FM_RADIO" >
+        <!-- /dev/fm is gid media, not audio -->
         <group gid="media" />
     </permission>
 
@@ -128,6 +129,12 @@
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
     <assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
 
+    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="audioserver" />
+    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="audioserver" />
+    <assign-permission name="android.permission.WAKE_LOCK" uid="audioserver" />
+    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
+    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
+
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
 
     <!-- This is a list of all the libraries available for application
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 3181017..d2bd106 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -17,11 +17,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# Use full Noto Sans Japanese font on non-smaller footprints
-ifneq ($(SMALLER_FONT_FOOTPRINT),true)
-FONT_NOTOSANS_JP_FULL := true
-endif
-
 ##########################################
 # create symlink for given font
 # $(1): new font $(2): link target
@@ -52,24 +47,6 @@
     DroidSans-Bold.ttf
 
 ################################
-# Do not include Motoya on space-constrained devices
-ifneq ($(SMALLER_FONT_FOOTPRINT),true)
-# Do not include Motoya if we are including Noto Sans Japanese
-ifneq ($(FONT_NOTOSANS_JP_FULL),true)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := MTLmr3m.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-include $(BUILD_PREBUILT)
-extra_font_files += MTLmr3m.ttf
-
-endif  # !FONT_NOTOSANS_JP_FULL
-endif  # !SMALLER_FONT_FOOTPRINT
-
-################################
 # Use DroidSansMono to hang extra_font_files on
 include $(CLEAR_VARS)
 LOCAL_MODULE := DroidSansMono.ttf
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 0e66374..554b6f1 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -330,16 +330,16 @@
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
     </family>
     <family lang="zh-Hans">
-        <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
+        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
     </family>
     <family lang="zh-Hant">
-        <font weight="400" style="normal">NotoSansTC-Regular.otf</font>
+        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
+        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
     </family>
     <family lang="ko">
-        <font weight="400" style="normal">NotoSansKR-Regular.otf</font>
+        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
     </family>
     <family>
         <font weight="400" style="normal">NanumGothic.ttf</font>
@@ -350,9 +350,6 @@
     <family>
         <font weight="400" style="normal">DroidSansFallback.ttf</font>
     </family>
-    <family lang="ja">
-        <font weight="400" style="normal">MTLmr3m.ttf</font>
-    </family>
     <!--
         Tai Le and Mongolian are intentionally kept last, to make sure they don't override
         the East Asian punctuation for Chinese.
diff --git a/docs/html/tools/help/index.jd b/docs/html/tools/help/index.jd
index f90d029..53247d1 100644
--- a/docs/html/tools/help/index.jd
+++ b/docs/html/tools/help/index.jd
@@ -100,10 +100,6 @@
   <dt><a href="{@docRoot}tools/help/traceview.html">traceview</a></dt>
     <dd>Provides a graphical viewer for execution logs saved by your application.</dd>
 
-  <dt><a href="{@docRoot}tools/help/systrace.html">Systrace</a></dt>
-    <dd>Lets you analyze the execution of your application in the context of system processes,
-    to help diagnose display and performance issues.</dd>
-
 </dl>
 
 
diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java
index 22d06c7..8c43252 100644
--- a/drm/java/android/drm/DrmInfo.java
+++ b/drm/java/android/drm/DrmInfo.java
@@ -17,6 +17,7 @@
 package android.drm;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 
@@ -52,7 +53,7 @@
         if (!isValid()) {
             final String msg = "infoType: " + infoType + "," +
                                "mimeType: " + mimeType + "," +
-                               "data: " + data;
+                               "data: " + Arrays.toString(data);
 
             throw new IllegalArgumentException(msg);
         }
@@ -79,7 +80,7 @@
         if (!isValid()) {
             final String msg = "infoType: " + infoType + "," +
                                "mimeType: " + mimeType + "," +
-                               "data: " + mData;
+                               "data: " + Arrays.toString(mData);
 
             throw new IllegalArgumentException();
         }
diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java
index a9b4f05..8747f77 100644
--- a/drm/java/android/drm/DrmRights.java
+++ b/drm/java/android/drm/DrmRights.java
@@ -18,6 +18,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
 
 /**
  * An entity class that wraps the license information retrieved from the online DRM server.
@@ -103,7 +104,7 @@
         mMimeType = mimeType;
         if (!isValid()) {
             final String msg = "mimeType: " + mMimeType + "," +
-                               "data: " + mData;
+                               "data: " + Arrays.toString(mData);
             throw new IllegalArgumentException(msg);
         }
     }
@@ -127,7 +128,7 @@
 
         if (!isValid()) {
             final String msg = "mimeType: " + mMimeType + "," +
-                               "data: " + mData;
+                               "data: " + Arrays.toString(mData);
             throw new IllegalArgumentException(msg);
         }
     }
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index b8b7e76..6309ed3 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -58,12 +58,12 @@
         }
     }
 
-    public boolean addFont(String path) {
-        return nAddFont(mNativePtr, path);
+    public boolean addFont(String path, int ttcIndex) {
+        return nAddFont(mNativePtr, path, ttcIndex);
     }
 
-    public boolean addFontWeightStyle(String path, int weight, boolean style) {
-        return nAddFontWeightStyle(mNativePtr, path, weight, style);
+    public boolean addFontWeightStyle(String path, int ttcIndex, int weight, boolean style) {
+        return nAddFontWeightStyle(mNativePtr, path, ttcIndex, weight, style);
     }
 
     public boolean addFontFromAsset(AssetManager mgr, String path) {
@@ -72,9 +72,9 @@
 
     private static native long nCreateFamily(String lang, int variant);
     private static native void nUnrefFamily(long nativePtr);
-    private static native boolean nAddFont(long nativeFamily, String path);
+    private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex);
     private static native boolean nAddFontWeightStyle(long nativeFamily, String path,
-            int weight, boolean isItalic);
+            int ttcIndex, int weight, boolean isItalic);
     private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
             String path);
 }
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 97081f9..774f6b8 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -43,12 +43,14 @@
     }
 
     public static class Font {
-        Font(String fontName, int weight, boolean isItalic) {
+        Font(String fontName, int ttcIndex, int weight, boolean isItalic) {
             this.fontName = fontName;
+            this.ttcIndex = ttcIndex;
             this.weight = weight;
             this.isItalic = isItalic;
         }
         public String fontName;
+        public int ttcIndex;
         public int weight;
         public boolean isItalic;
     }
@@ -112,12 +114,14 @@
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("font")) {
+                String ttcIndexStr = parser.getAttributeValue(null, "index");
+                int ttcIndex = ttcIndexStr == null ? 0 : Integer.parseInt(ttcIndexStr);
                 String weightStr = parser.getAttributeValue(null, "weight");
                 int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
                 boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
                 String filename = parser.nextText();
                 String fullFilename = "/system/fonts/" + filename;
-                fonts.add(new Font(fullFilename, weight, isItalic));
+                fonts.add(new Font(fullFilename, ttcIndex, weight, isItalic));
             } else {
                 skip(parser);
             }
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 7aa0aef..a226e85 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -361,6 +361,17 @@
     public static final int RAW_SENSOR = 0x20;
 
     /**
+     * <p>Private raw camera sensor image format, a single channel image with
+     * implementation depedent pixel layout.</p>
+     *
+     * <p>RAW_PRIVATE is a format for unprocessed raw image buffers coming from an
+     * image sensor. The actual structure of buffers of this format is
+     * implementation-dependent.</p>
+     *
+     */
+    public static final int RAW_PRIVATE = 0x24;
+
+    /**
      * <p>
      * Android 10-bit raw format
      * </p>
@@ -748,6 +759,7 @@
             case FLEX_RGB_888:
             case FLEX_RGBA_8888:
             case RAW_SENSOR:
+            case RAW_PRIVATE:
             case RAW10:
             case RAW12:
             case DEPTH16:
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 7eb5584..1294323 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -209,7 +209,7 @@
     public static Typeface createFromFile(String path) {
         if (sFallbackFonts != null) {
             FontFamily fontFamily = new FontFamily();
-            if (fontFamily.addFont(path)) {
+            if (fontFamily.addFont(path, 0 /* ttcIndex */)) {
                 FontFamily[] families = { fontFamily };
                 return createFromFamiliesWithDefault(families);
             }
@@ -262,7 +262,7 @@
     private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
         FontFamily fontFamily = new FontFamily(family.lang, family.variant);
         for (FontListParser.Font font : family.fonts) {
-            fontFamily.addFontWeightStyle(font.fontName, font.weight, font.isItalic);
+            fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.weight, font.isItalic);
         }
         return fontFamily;
     }
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index ed83314..b1e552a 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -45,7 +45,9 @@
     RAW_SENSOR        = 0x20,
     PRIVATE           = 0x22,
     YUV_420_888       = 0x23,
+    RAW_PRIVATE       = 0x24,
     RAW10             = 0x25,
+    RAW12             = 0x26,
     JPEG              = 0x100,
     DEPTH_POINT_CLOUD = 0x101,
     YV12              = 0x32315659,
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index fde12dd..6ba23e9 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -20,6 +20,8 @@
 #include "Caches.h"
 #include "Glop.h"
 #include "GlopBuilder.h"
+#include "Patch.h"
+#include "PathTessellator.h"
 #include "renderstate/OffscreenBufferPool.h"
 #include "renderstate/RenderState.h"
 #include "utils/GLUtils.h"
@@ -27,6 +29,7 @@
 
 #include <algorithm>
 #include <math.h>
+#include <SkPaintDefaults.h>
 
 namespace android {
 namespace uirenderer {
@@ -54,8 +57,6 @@
     if (entry) {
         entry->uvMapper.map(texCoords);
     }
-    // init to non-empty, so we can safely expandtoCoverRect
-    Rect totalBounds = firstState.computedState.clippedBounds;
     for (size_t i = 0; i < opList.count; i++) {
         const BakedOpState& state = *(opList.states[i]);
         TextureVertex* rectVerts = &vertices[i * 4];
@@ -66,8 +67,6 @@
         }
         storeTexturedRect(rectVerts, opBounds, texCoords);
         renderer.dirtyRenderTarget(opBounds);
-
-        totalBounds.expandToCover(opBounds);
     }
 
     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
@@ -78,7 +77,111 @@
             .setMeshTexturedIndexedQuads(vertices, opList.count * 6)
             .setFillTexturePaint(*texture, textureFillFlags, firstState.op->paint, firstState.alpha)
             .setTransform(Matrix4::identity(), TransformFlags::None)
-            .setModelViewOffsetRect(0, 0, totalBounds) // don't snap here, we snap per-quad above
+            .setModelViewIdentityEmptyBounds()
+            .build();
+    renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+}
+
+void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
+        const MergedBakedOpList& opList) {
+    const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op));
+    const BakedOpState& firstState = *(opList.states[0]);
+    AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(
+            firstOp.bitmap->pixelRef());
+
+    // Batches will usually contain a small number of items so it's
+    // worth performing a first iteration to count the exact number
+    // of vertices we need in the new mesh
+    uint32_t totalVertices = 0;
+
+    for (size_t i = 0; i < opList.count; i++) {
+        const PatchOp& op = *(static_cast<const PatchOp*>(opList.states[i]->op));
+
+        // TODO: cache mesh lookups
+        const Patch* opMesh = renderer.caches().patchCache.get(
+                entry, op.bitmap->width(), op.bitmap->height(),
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+        totalVertices += opMesh->verticesCount;
+    }
+
+    const bool dirtyRenderTarget = renderer.offscreenRenderTarget();
+
+    uint32_t indexCount = 0;
+
+    TextureVertex vertices[totalVertices];
+    TextureVertex* vertex = &vertices[0];
+    // Create a mesh that contains the transformed vertices for all the
+    // 9-patch objects that are part of the batch. Note that onDefer()
+    // enforces ops drawn by this function to have a pure translate or
+    // identity matrix
+    for (size_t i = 0; i < opList.count; i++) {
+        const PatchOp& op = *(static_cast<const PatchOp*>(opList.states[i]->op));
+        const BakedOpState& state = *opList.states[i];
+
+        // TODO: cache mesh lookups
+        const Patch* opMesh = renderer.caches().patchCache.get(
+                entry, op.bitmap->width(), op.bitmap->height(),
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+
+
+        uint32_t vertexCount = opMesh->verticesCount;
+        if (vertexCount == 0) continue;
+
+        // We use the bounds to know where to translate our vertices
+        // Using patchOp->state.mBounds wouldn't work because these
+        // bounds are clipped
+        const float tx = floorf(state.computedState.transform.getTranslateX()
+                + op.unmappedBounds.left + 0.5f);
+        const float ty = floorf(state.computedState.transform.getTranslateY()
+                + op.unmappedBounds.top + 0.5f);
+
+        // Copy & transform all the vertices for the current operation
+        TextureVertex* opVertices = opMesh->vertices.get();
+        for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
+            TextureVertex::set(vertex++,
+                    opVertices->x + tx, opVertices->y + ty,
+                    opVertices->u, opVertices->v);
+        }
+
+        // Dirty the current layer if possible. When the 9-patch does not
+        // contain empty quads we can take a shortcut and simply set the
+        // dirty rect to the object's bounds.
+        if (dirtyRenderTarget) {
+            if (!opMesh->hasEmptyQuads) {
+                renderer.dirtyRenderTarget(Rect(tx, ty,
+                        tx + op.unmappedBounds.getWidth(), ty + op.unmappedBounds.getHeight()));
+            } else {
+                const size_t count = opMesh->quads.size();
+                for (size_t i = 0; i < count; i++) {
+                    const Rect& quadBounds = opMesh->quads[i];
+                    const float x = tx + quadBounds.left;
+                    const float y = ty + quadBounds.top;
+                    renderer.dirtyRenderTarget(Rect(x, y,
+                            x + quadBounds.getWidth(), y + quadBounds.getHeight()));
+                }
+            }
+        }
+
+        indexCount += opMesh->indexCount;
+    }
+
+
+    Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(firstOp.bitmap);
+    if (!texture) return;
+    const AutoTexture autoCleanup(texture);
+
+    // 9 patches are built for stretching - always filter
+    int textureFillFlags = TextureFillFlags::ForceFilter;
+    if (firstOp.bitmap->colorType() == kAlpha_8_SkColorType) {
+        textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
+    }
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(firstState.roundRectClipState)
+            .setMeshTexturedIndexedQuads(vertices, indexCount)
+            .setFillTexturePaint(*texture, textureFillFlags, firstOp.paint, firstState.alpha)
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewIdentityEmptyBounds()
             .build();
     renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
 }
@@ -206,6 +309,98 @@
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
+void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) {
+    LOG_ALWAYS_FATAL("unsupported operation");
+}
+
+void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) {
+    LOG_ALWAYS_FATAL("unsupported operation");
+}
+
+namespace VertexBufferRenderFlags {
+    enum {
+        Offset = 0x1,
+        ShadowInterp = 0x2,
+    };
+}
+
+static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
+        const VertexBuffer& vertexBuffer, float translateX, float translateY,
+        const SkPaint& paint, int vertexBufferRenderFlags) {
+    if (CC_LIKELY(vertexBuffer.getVertexCount())) {
+        bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
+        const int transformFlags = TransformFlags::OffsetByFudgeFactor;
+        Glop glop;
+        GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+                .setRoundRectClipState(state.roundRectClipState)
+                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
+                .setFillPaint(paint, state.alpha)
+                .setTransform(state.computedState.transform, transformFlags)
+                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
+                .build();
+        renderer.renderGlop(state, glop);
+    }
+}
+
+static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& state,
+        const SkPath& path, const SkPaint& paint) {
+    VertexBuffer vertexBuffer;
+    // TODO: try clipping large paths to viewport
+    PathTessellator::tessellatePath(path, &paint, state.computedState.transform, vertexBuffer);
+    renderVertexBuffer(renderer, state, vertexBuffer, 0.0f, 0.0f, paint, 0);
+}
+
+static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
+        PathTexture& texture, const RecordedOp& op) {
+    Rect dest(texture.width, texture.height);
+    dest.translate(texture.left + op.unmappedBounds.left - texture.offset,
+            texture.top + op.unmappedBounds.top - texture.offset);
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshTexturedUnitQuad(nullptr)
+            .setFillPathTexturePaint(texture, *(op.paint), state.alpha)
+            .setTransform(state.computedState.transform,  TransformFlags::None)
+            .setModelViewMapUnitToRect(dest)
+            .build();
+    renderer.renderGlop(state, glop);
+}
+
+SkRect getBoundsOfFill(const RecordedOp& op) {
+    SkRect bounds = op.unmappedBounds.toSkRect();
+    if (op.paint->getStyle() == SkPaint::kStrokeAndFill_Style) {
+        float outsetDistance = op.paint->getStrokeWidth() / 2;
+        bounds.outset(outsetDistance, outsetDistance);
+    }
+    return bounds;
+}
+
+void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, const BakedOpState& state) {
+    // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
+    if (op.paint->getStyle() != SkPaint::kStroke_Style
+            || op.paint->getPathEffect() != nullptr
+            || op.useCenter) {
+        PathTexture* texture = renderer.caches().pathCache.getArc(
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
+                op.startAngle, op.sweepAngle, op.useCenter, op.paint);
+        const AutoTexture holder(texture);
+        if (CC_LIKELY(holder.texture)) {
+            renderPathTexture(renderer, state, *texture, op);
+        }
+    } else {
+        SkRect rect = getBoundsOfFill(op);
+        SkPath path;
+        if (op.useCenter) {
+            path.moveTo(rect.centerX(), rect.centerY());
+        }
+        path.arcTo(rect, op.startAngle, op.sweepAngle, !op.useCenter);
+        if (op.useCenter) {
+            path.close();
+        }
+        renderConvexPath(renderer, state, path, *(op.paint));
+    }
+}
+
 void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
     Texture* texture = renderer.getTexture(op.bitmap);
     if (!texture) return;
@@ -219,49 +414,235 @@
             .setMeshTexturedUnitQuad(texture->uvMapper)
             .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
-            .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+            .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height))
+            .build();
+    renderer.renderGlop(state, glop);
+}
+
+void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) {
+    const static UvMapper defaultUvMapper;
+    const uint32_t elementCount = op.meshWidth * op.meshHeight * 6;
+
+    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
+    ColorTextureVertex* vertex = &mesh[0];
+
+    const int* colors = op.colors;
+    std::unique_ptr<int[]> tempColors;
+    if (!colors) {
+        uint32_t colorsCount = (op.meshWidth + 1) * (op.meshHeight + 1);
+        tempColors.reset(new int[colorsCount]);
+        memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
+        colors = tempColors.get();
+    }
+
+    Texture* texture = renderer.renderState().assetAtlas().getEntryTexture(op.bitmap->pixelRef());
+    const UvMapper& mapper(texture && texture->uvMapper ? *texture->uvMapper : defaultUvMapper);
+
+    for (int32_t y = 0; y < op.meshHeight; y++) {
+        for (int32_t x = 0; x < op.meshWidth; x++) {
+            uint32_t i = (y * (op.meshWidth + 1) + x) * 2;
+
+            float u1 = float(x) / op.meshWidth;
+            float u2 = float(x + 1) / op.meshWidth;
+            float v1 = float(y) / op.meshHeight;
+            float v2 = float(y + 1) / op.meshHeight;
+
+            mapper.map(u1, v1, u2, v2);
+
+            int ax = i + (op.meshWidth + 1) * 2;
+            int ay = ax + 1;
+            int bx = i;
+            int by = bx + 1;
+            int cx = i + 2;
+            int cy = cx + 1;
+            int dx = i + (op.meshWidth + 1) * 2 + 2;
+            int dy = dx + 1;
+
+            const float* vertices = op.vertices;
+            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
+            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
+
+            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
+            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
+        }
+    }
+
+    if (!texture) {
+        texture = renderer.caches().textureCache.get(op.bitmap);
+        if (!texture) {
+            return;
+        }
+    }
+    const AutoTexture autoCleanup(texture);
+
+    /*
+     * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
+     * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
+     */
+    const int textureFillFlags = TextureFillFlags::None;
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshColoredTexturedMesh(mesh.get(), elementCount)
+            .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+            .setTransform(state.computedState.transform,  TransformFlags::None)
+            .setModelViewOffsetRect(0, 0, op.unmappedBounds)
+            .build();
+    renderer.renderGlop(state, glop);
+}
+
+void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, const BakedOpState& state) {
+    Texture* texture = renderer.getTexture(op.bitmap);
+    if (!texture) return;
+    const AutoTexture autoCleanup(texture);
+
+    Rect uv(std::max(0.0f, op.src.left / texture->width),
+            std::max(0.0f, op.src.top / texture->height),
+            std::min(1.0f, op.src.right / texture->width),
+            std::min(1.0f, op.src.bottom / texture->height));
+
+    const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
+            ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+    const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth())
+            && MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshTexturedUvQuad(texture->uvMapper, uv)
+            .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
             .build();
     renderer.renderGlop(state, glop);
 }
 
 void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) {
-    LOG_ALWAYS_FATAL("todo");
+    VertexBuffer buffer;
+    PathTessellator::tessellateLines(op.points, op.floatCount, op.paint,
+            state.computedState.transform, buffer);
+    int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
+    renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
 }
 
-void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, const BakedOpState& state) {
+    if (op.paint->getPathEffect() != nullptr) {
+        PathTexture* texture = renderer.caches().pathCache.getOval(
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
+        const AutoTexture holder(texture);
+        if (CC_LIKELY(holder.texture)) {
+            renderPathTexture(renderer, state, *texture, op);
+        }
+    } else {
+        SkPath path;
+        SkRect rect = getBoundsOfFill(op);
+        path.addOval(rect);
+        renderConvexPath(renderer, state, path, *(op.paint));
+    }
+}
+
+void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) {
+    // 9 patches are built for stretching - always filter
+    int textureFillFlags = TextureFillFlags::ForceFilter;
+    if (op.bitmap->colorType() == kAlpha_8_SkColorType) {
+        textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
+    }
+
+    // TODO: avoid redoing the below work each frame:
+    AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(op.bitmap->pixelRef());
+    const Patch* mesh = renderer.caches().patchCache.get(
+            entry, op.bitmap->width(), op.bitmap->height(),
+            op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+
+    Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(op.bitmap);
+    if (!texture) return;
+    const AutoTexture autoCleanup(texture);
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
-            .setMeshUnitQuad()
-            .setFillPaint(*op.paint, state.alpha)
+            .setMeshPatchQuads(*mesh)
+            .setMeshTexturedUnitQuad(texture->uvMapper)
+            .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
-            .setModelViewMapUnitToRect(op.unmappedBounds)
+            .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+                    Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
             .build();
     renderer.renderGlop(state, glop);
 }
 
-namespace VertexBufferRenderFlags {
-    enum {
-        Offset = 0x1,
-        ShadowInterp = 0x2,
-    };
+void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
+    PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
+    const AutoTexture holder(texture);
+    if (CC_LIKELY(holder.texture)) {
+        renderPathTexture(renderer, state, *texture, op);
+    }
 }
 
-static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
-        const VertexBuffer& vertexBuffer, float translateX, float translateY,
-        SkPaint& paint, int vertexBufferRenderFlags) {
-    if (CC_LIKELY(vertexBuffer.getVertexCount())) {
-        bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
-        const int transformFlags = TransformFlags::OffsetByFudgeFactor;
-        Glop glop;
-        GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
-                .setRoundRectClipState(state.roundRectClipState)
-                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
-                .setFillPaint(paint, state.alpha)
-                .setTransform(state.computedState.transform, transformFlags)
-                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
-                .build();
-        renderer.renderGlop(state, glop);
+void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, const BakedOpState& state) {
+    VertexBuffer buffer;
+    PathTessellator::tessellatePoints(op.points, op.floatCount, op.paint,
+            state.computedState.transform, buffer);
+    int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
+    renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
+}
+
+// See SkPaintDefaults.h
+#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
+
+void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
+    if (op.paint->getStyle() != SkPaint::kFill_Style) {
+        // only fill + default miter is supported by drawConvexPath, since others must handle joins
+        static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
+        if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr
+                || op.paint->getStrokeJoin() != SkPaint::kMiter_Join
+                || op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
+             PathTexture* texture = renderer.caches().pathCache.getRect(
+                     op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
+             const AutoTexture holder(texture);
+             if (CC_LIKELY(holder.texture)) {
+                 renderPathTexture(renderer, state, *texture, op);
+             }
+        } else {
+            SkPath path;
+            path.addRect(getBoundsOfFill(op));
+            renderConvexPath(renderer, state, path, *(op.paint));
+        }
+    } else {
+        if (op.paint->isAntiAlias() && !state.computedState.transform.isSimple()) {
+            SkPath path;
+            path.addRect(op.unmappedBounds.toSkRect());
+            renderConvexPath(renderer, state, path, *(op.paint));
+        } else {
+            // render simple unit quad, no tessellation required
+            Glop glop;
+            GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+                    .setRoundRectClipState(state.roundRectClipState)
+                    .setMeshUnitQuad()
+                    .setFillPaint(*op.paint, state.alpha)
+                    .setTransform(state.computedState.transform, TransformFlags::None)
+                    .setModelViewMapUnitToRect(op.unmappedBounds)
+                    .build();
+            renderer.renderGlop(state, glop);
+        }
+    }
+}
+
+void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, const BakedOpState& state) {
+    if (op.paint->getPathEffect() != nullptr) {
+        PathTexture* texture = renderer.caches().pathCache.getRoundRect(
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
+                op.rx, op.ry, op.paint);
+        const AutoTexture holder(texture);
+        if (CC_LIKELY(holder.texture)) {
+            renderPathTexture(renderer, state, *texture, op);
+        }
+    } else {
+        const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect(
+                state.computedState.transform, *(op.paint),
+                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
+        renderVertexBuffer(renderer, state, *buffer,
+                op.unmappedBounds.left, op.unmappedBounds.top, *(op.paint), 0);
     }
 }
 
@@ -323,8 +704,6 @@
 void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
     OffscreenBuffer* buffer = *op.layerHandle;
 
-    // TODO: extend this to handle HW layers & paint properties which
-    // reside in node.properties().layerProperties()
     float layerAlpha = op.alpha * state.alpha;
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h
index 0e763d9..ed34ada 100644
--- a/libs/hwui/BakedOpDispatcher.h
+++ b/libs/hwui/BakedOpDispatcher.h
@@ -26,6 +26,10 @@
 /**
  * Provides all "onBitmapOp(...)" style static methods for every op type, which convert the
  * RecordedOps and their state to Glops, and renders them with the provided BakedOpRenderer.
+ *
+ * onXXXOp methods must either render directly with the renderer, or call a static renderYYY
+ * method to render content. There should never be draw content rejection in BakedOpDispatcher -
+ * it must happen at a higher level (except in error-ish cases, like texture-too-big).
  */
 class BakedOpDispatcher {
 public:
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 983c27b..9c836a0 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -53,7 +53,7 @@
 class ResolvedRenderState {
 public:
     // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
-    ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp) {
+    ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) {
         /* TODO: benchmark a fast path for translate-only matrices, such as:
         if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
                 && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
@@ -83,7 +83,17 @@
 
         // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
         clippedBounds = recordedOp.unmappedBounds;
+        if (CC_UNLIKELY(expandForStroke)) {
+            // account for non-hairline stroke
+            clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+        }
         transform.mapRect(clippedBounds);
+        if (CC_UNLIKELY(expandForStroke
+                && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+            // account for hairline stroke when stroke may be < 1 scaled pixel
+            // Non translate || strokeWidth < 1 is conservative, but will cover all cases
+            clippedBounds.outset(0.5f);
+        }
 
         if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
         if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
@@ -129,13 +139,36 @@
 public:
     static BakedOpState* tryConstruct(LinearAllocator& allocator,
             const Snapshot& snapshot, const RecordedOp& recordedOp) {
-        BakedOpState* bakedOp = new (allocator) BakedOpState(snapshot, recordedOp);
-        if (bakedOp->computedState.clippedBounds.isEmpty()) {
+        BakedOpState* bakedState = new (allocator) BakedOpState(snapshot, recordedOp, false);
+        if (bakedState->computedState.clippedBounds.isEmpty()) {
             // bounds are empty, so op is rejected
-            allocator.rewindIfLastAlloc(bakedOp);
+            allocator.rewindIfLastAlloc(bakedState);
             return nullptr;
         }
-        return bakedOp;
+        return bakedState;
+    }
+
+    enum class StrokeBehavior {
+        // stroking is forced, regardless of style on paint
+        Forced,
+        // stroking is defined by style on paint
+        StyleDefined,
+    };
+
+    static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
+            const Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+        bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
+                ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
+                : true;
+
+        BakedOpState* bakedState = new (allocator) BakedOpState(
+                snapshot, recordedOp, expandForStroke);
+        if (bakedState->computedState.clippedBounds.isEmpty()) {
+            // bounds are empty, so op is rejected
+            allocator.rewindIfLastAlloc(bakedState);
+            return nullptr;
+        }
+        return bakedState;
     }
 
     static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
@@ -160,8 +193,8 @@
     const RecordedOp* op;
 
 private:
-    BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp)
-            : computedState(snapshot, recordedOp)
+    BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke)
+            : computedState(snapshot, recordedOp, expandForStroke)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
             , projectionPathMask(snapshot.projectionPathMask)
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 94a11f1..eaa1c33 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -103,7 +103,7 @@
 
 void Caches::terminate() {
     if (!mInitialized) return;
-    mRegionMesh.release();
+    mRegionMesh.reset(nullptr);
 
     fboCache.clear();
 
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index b585a27..0643a54 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -113,10 +113,10 @@
 
     // Geometry
     virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0;
+    virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
                 const SkPaint& paint) = 0;
-    virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0;
+    virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
     virtual void drawRect(float left, float top, float right, float bottom,
             const SkPaint& paint) = 0;
     virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9c8649f..ed31a2c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -73,7 +73,7 @@
             .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
             .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
             .setTransform(bakedState->computedState.transform, transformFlags)
-            .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+            .setModelViewIdentityEmptyBounds()
             .build();
     // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
     renderer->renderGlop(nullptr, clip, glop);
@@ -83,7 +83,7 @@
             .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
             .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
             .setTransform(*(renderer->currentSnapshot()), transformFlags)
-            .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+            .setModelViewOffsetRect(0, 0, Rect())
             .build();
     renderer->renderGlop(glop);
 #endif
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 146d385..5813e7f 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -30,7 +30,7 @@
     GammaFontRenderer();
 
     void clear() {
-        mRenderer.release();
+        mRenderer.reset(nullptr);
     }
 
     void flush() {
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 4785ea4..bcf819e 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -64,7 +64,7 @@
 
         // Canvas transform isn't applied to the mesh at draw time,
         //since it's already built in.
-        MeshIgnoresCanvasTransform = 1 << 1,
+        MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove
     };
 };
 
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index f3ac93b..2507ff3 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -101,7 +101,7 @@
 GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
     if (uvMapper) {
         // can't use unit quad VBO, so build UV vertices manually
-        return setMeshTexturedUvQuad(uvMapper, Rect(0, 0, 1, 1));
+        return setMeshTexturedUvQuad(uvMapper, Rect(1, 1));
     }
 
     TRIGGER_STAGE(kMeshStage);
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index b647b90..6e5797d 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -95,6 +95,10 @@
             return setModelViewOffsetRect(offsetX, offsetY, source);
         }
     }
+    GlopBuilder& setModelViewIdentityEmptyBounds() {
+        // pass empty rect since not needed for damage / snap
+        return setModelViewOffsetRect(0, 0, Rect());
+    }
 
     GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 489ebc1..0fe20ad 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -248,7 +248,7 @@
 void Layer::cancelDefer() {
     renderNode = nullptr;
     deferredUpdateScheduled = false;
-    deferredList.release();
+    deferredList.reset(nullptr);
 }
 
 void Layer::flush() {
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 9460361..ec03e83 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -467,13 +467,13 @@
             // (temp layers are clipped to viewport, since they don't persist offscreen content)
             SkPaint saveLayerPaint;
             saveLayerPaint.setAlpha(properties.getAlpha());
-            onBeginLayerOp(*new (mAllocator) BeginLayerOp(
+            deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
                     saveLayerBounds,
                     Matrix4::identity(),
                     saveLayerBounds,
                     &saveLayerPaint));
             deferNodeOps(node);
-            onEndLayerOp(*new (mAllocator) EndLayerOp());
+            deferEndLayerOp(*new (mAllocator) EndLayerOp());
         } else {
             deferNodeOps(node);
         }
@@ -559,7 +559,7 @@
         }
 
         const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
-        deferRenderNodeOp(*childOp);
+        deferRenderNodeOpImpl(*childOp);
         drawIndex++;
     }
 }
@@ -645,7 +645,7 @@
 
         int restoreTo = mCanvasState.save(SkCanvas::kMatrix_SaveFlag);
         mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
-        deferRenderNodeOp(*childOp);
+        deferRenderNodeOpImpl(*childOp);
         mCanvasState.restoreToCount(restoreTo);
     }
 
@@ -653,13 +653,13 @@
 }
 
 /**
- * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
+ * Used to define a list of lambdas referencing private OpReorderer::onXX::defer() methods.
  *
  * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
  * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&)
  */
 #define OP_RECEIVER(Type) \
-        [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
+        [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); },
 void OpReorderer::deferNodeOps(const RenderNode& renderNode) {
     typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op);
     static OpDispatcher receivers[] = {
@@ -687,7 +687,7 @@
     }
 }
 
-void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) {
+void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) {
     if (op.renderNode->nothingToDraw()) return;
     int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
 
@@ -702,19 +702,43 @@
     mCanvasState.restoreToCount(count);
 }
 
-void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
+void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) {
     if (!op.skipInOrderDraw) {
-        deferRenderNodeOp(op);
+        deferRenderNodeOpImpl(op);
     }
 }
 
-static batchid_t tessellatedBatchId(const SkPaint& paint) {
+/**
+ * Defers an unmergeable, strokeable op, accounting correctly
+ * for paint's style on the bounds being computed.
+ */
+void OpReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+        BakedOpState::StrokeBehavior strokeBehavior) {
+    // Note: here we account for stroke when baking the op
+    BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
+            mAllocator, *mCanvasState.currentSnapshot(), op, strokeBehavior);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
+}
+
+/**
+ * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will
+ * be used, since they trigger significantly different rendering paths.
+ *
+ * Note: not used for lines/points, since they don't currently support path effects.
+ */
+static batchid_t tessBatchId(const RecordedOp& op) {
+    const SkPaint& paint = *(op.paint);
     return paint.getPathEffect()
             ? OpBatchType::AlphaMaskTexture
             : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
 }
 
-void OpReorderer::onBitmapOp(const BitmapOp& op) {
+void OpReorderer::deferArcOp(const ArcOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void OpReorderer::deferBitmapOp(const BitmapOp& op) {
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
 
@@ -733,25 +757,94 @@
     }
 }
 
-void OpReorderer::onLinesOp(const LinesOp& op) {
+void OpReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) {
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, tessellatedBatchId(*op.paint));
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
 }
 
-void OpReorderer::onRectOp(const RectOp& op) {
+void OpReorderer::deferBitmapRectOp(const BitmapRectOp& op) {
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, tessellatedBatchId(*op.paint));
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
 }
 
-void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) {
+void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) {
+    // allocate a temporary oval op (with mAllocator, so it persists until render), so the
+    // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
+    float x = *(op.x);
+    float y = *(op.y);
+    float radius = *(op.radius);
+    Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
+    const OvalOp* resolvedOp = new (mAllocator) OvalOp(
+            unmappedBounds,
+            op.localMatrix,
+            op.localClipRect,
+            op.paint);
+    deferOvalOp(*resolvedOp);
+}
+
+void OpReorderer::deferLinesOp(const LinesOp& op) {
+    batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
+    deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
+}
+
+void OpReorderer::deferOvalOp(const OvalOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void OpReorderer::deferPatchOp(const PatchOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+
+    if (bakedState->computedState.transform.isPureTranslate()
+            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) {
+        mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
+        // TODO: AssetAtlas in mergeId
+
+        // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
+        currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId);
+    } else {
+        // Use Bitmap batchId since Bitmap+Patch use same shader
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+    }
+}
+
+void OpReorderer::deferPathOp(const PathOp& op) {
+    deferStrokeableOp(op, OpBatchType::Bitmap);
+}
+
+void OpReorderer::deferPointsOp(const PointsOp& op) {
+    batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
+    deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
+}
+
+void OpReorderer::deferRectOp(const RectOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void OpReorderer::deferRoundRectOp(const RoundRectOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
+    // allocate a temporary round rect op (with mAllocator, so it persists until render), so the
+    // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
+    const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
+            Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
+            op.localMatrix,
+            op.localClipRect,
+            op.paint, *op.rx, *op.ry);
+    deferRoundRectOp(*resolvedOp);
+}
+
+void OpReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) {
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
 }
 
-void OpReorderer::onTextOp(const TextOp& op) {
+void OpReorderer::deferTextOp(const TextOp& op) {
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
 
@@ -794,7 +887,7 @@
 }
 
 // TODO: test rejection at defer time, where the bounds become empty
-void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) {
+void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) {
     uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
     uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
 
@@ -839,7 +932,7 @@
             &op, nullptr);
 }
 
-void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) {
+void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) {
     const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp;
     int finishedLayerIndex = mLayerStack.back();
 
@@ -865,11 +958,11 @@
     }
 }
 
-void OpReorderer::onLayerOp(const LayerOp& op) {
+void OpReorderer::deferLayerOp(const LayerOp& op) {
     LOG_ALWAYS_FATAL("unsupported");
 }
 
-void OpReorderer::onShadowOp(const ShadowOp& op) {
+void OpReorderer::deferShadowOp(const ShadowOp& op) {
     LOG_ALWAYS_FATAL("unsupported");
 }
 
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index fc77c61..35343c8b 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -45,7 +45,7 @@
     enum {
         None = 0, // Don't batch
         Bitmap,
-        Patch,
+        MergedPatch,
         AlphaVertices,
         Vertices,
         AlphaMaskTexture,
@@ -237,7 +237,7 @@
 
     void deferNodeOps(const RenderNode& renderNode);
 
-    void deferRenderNodeOp(const RenderNodeOp& op);
+    void deferRenderNodeOpImpl(const RenderNodeOp& op);
 
     void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
 
@@ -245,14 +245,18 @@
         mFrameAllocatedPaths.emplace_back(new SkPath);
         return mFrameAllocatedPaths.back().get();
     }
+
+    void deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+            BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
+
     /**
-     * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type.
+     * Declares all OpReorderer::deferXXXXOp() methods for every RecordedOp type.
      *
      * These private methods are called from within deferImpl to defer each individual op
      * type differently.
      */
 #define INTERNAL_OP_HANDLER(Type) \
-    void on##Type(const Type& op);
+    void defer##Type(const Type& op);
     MAP_OPS(INTERNAL_OP_HANDLER)
 
     std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2cb32c4..92b758d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -40,6 +40,7 @@
 
 #include <SkCanvas.h>
 #include <SkColor.h>
+#include <SkPaintDefaults.h>
 #include <SkPathOps.h>
 #include <SkShader.h>
 #include <SkTypeface.h>
@@ -1473,7 +1474,7 @@
             .setMeshTexturedMesh(vertices, bitmapCount * 6)
             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(), transformFlags)
-            .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
+            .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(bounds.getWidth(), bounds.getHeight()))
             .build();
     renderGlop(glop, GlopRenderType::Multi);
 }
@@ -1496,7 +1497,7 @@
             .setMeshTexturedUnitQuad(texture->uvMapper)
             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(),  TransformFlags::None)
-            .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+            .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height))
             .build();
     renderGlop(glop);
 }
@@ -1641,7 +1642,7 @@
             .setMeshPatchQuads(*mesh)
             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(),  TransformFlags::None)
-            .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
+            .setModelViewOffsetRectSnap(left, top, Rect(right - left, bottom - top)) // TODO: get minimal bounds from patch
             .build();
     renderGlop(glop);
 }
@@ -1671,7 +1672,7 @@
             .setMeshTexturedIndexedQuads(vertices, elementCount)
             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(), transformFlags)
-            .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+            .setModelViewOffsetRect(0, 0, Rect())
             .build();
     renderGlop(glop, GlopRenderType::Multi);
 }
@@ -1908,9 +1909,6 @@
     drawConvexPath(path, p);
 }
 
-// See SkPaintDefaults.h
-#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
-
 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
         const SkPaint* p) {
     if (mState.currentlyIgnored()
@@ -1921,6 +1919,7 @@
 
     if (p->getStyle() != SkPaint::kFill_Style) {
         // only fill style is supported by drawConvexPath, since others have to handle joins
+        static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
         if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
             mCaches.textureState().activateTexture(0);
@@ -2269,7 +2268,7 @@
                     .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
                     .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
                     .setTransform(*currentSnapshot(),  TransformFlags::None)
-                    .setModelViewOffsetRectSnap(0, 0, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+                    .setModelViewOffsetRectSnap(0, 0, Rect(layer->layer.getWidth(), layer->layer.getHeight()))
                     .build();
             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
 #if DEBUG_LAYERS_AS_REGIONS
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index b966401..cd7a4bb 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -24,7 +24,8 @@
 #include "utils/LinearAllocator.h"
 #include "Vector.h"
 
-#include "SkXfermode.h"
+#include <androidfw/ResourceTypes.h>
+#include <SkXfermode.h>
 
 class SkBitmap;
 class SkPaint;
@@ -43,10 +44,20 @@
  * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs.
  */
 #define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \
+        U_OP_FN(ArcOp) \
         M_OP_FN(BitmapOp) \
+        U_OP_FN(BitmapMeshOp) \
+        U_OP_FN(BitmapRectOp) \
+        U_OP_FN(CirclePropsOp) \
         U_OP_FN(LinesOp) \
+        U_OP_FN(OvalOp) \
+        M_OP_FN(PatchOp) \
+        U_OP_FN(PathOp) \
+        U_OP_FN(PointsOp) \
         U_OP_FN(RectOp) \
         U_OP_FN(RenderNodeOp) \
+        U_OP_FN(RoundRectOp) \
+        U_OP_FN(RoundRectPropsOp) \
         U_OP_FN(ShadowOp) \
         U_OP_FN(SimpleRectsOp) \
         M_OP_FN(TextOp) \
@@ -74,7 +85,7 @@
         Count,
     };
 }
-static_assert(RecordedOpId::BitmapOp == 0,
+static_assert(RecordedOpId::ArcOp == 0,
         "First index must be zero for LUTs to work");
 
 #define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
@@ -86,7 +97,7 @@
     /* ID from RecordedOpId - generally used for jumping into function tables */
     const int opId;
 
-    /* bounds in *local* space, without accounting for DisplayList transformation */
+    /* bounds in *local* space, without accounting for DisplayList transformation, or stroke */
     const Rect unmappedBounds;
 
     /* transform in recording space (vs DisplayList origin) */
@@ -128,6 +139,17 @@
 // Standard Ops
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+struct ArcOp : RecordedOp {
+    ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter)
+            : SUPER(ArcOp)
+            , startAngle(startAngle)
+            , sweepAngle(sweepAngle)
+            , useCenter(useCenter) {}
+    const float startAngle;
+    const float sweepAngle;
+    const bool useCenter;
+};
+
 struct BitmapOp : RecordedOp {
     BitmapOp(BASE_PARAMS, const SkBitmap* bitmap)
             : SUPER(BitmapOp)
@@ -136,6 +158,43 @@
     // TODO: asset atlas/texture id lookup?
 };
 
+struct BitmapMeshOp : RecordedOp {
+    BitmapMeshOp(BASE_PARAMS, const SkBitmap* bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors)
+            : SUPER(BitmapMeshOp)
+            , bitmap(bitmap)
+            , meshWidth(meshWidth)
+            , meshHeight(meshHeight)
+            , vertices(vertices)
+            , colors(colors) {}
+    const SkBitmap* bitmap;
+    const int meshWidth;
+    const int meshHeight;
+    const float* vertices;
+    const int* colors;
+};
+
+struct BitmapRectOp : RecordedOp {
+    BitmapRectOp(BASE_PARAMS, const SkBitmap* bitmap, const Rect& src)
+            : SUPER(BitmapRectOp)
+            , bitmap(bitmap)
+            , src(src) {}
+    const SkBitmap* bitmap;
+    const Rect src;
+};
+
+struct CirclePropsOp : RecordedOp {
+    CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+            float* x, float* y, float* radius)
+            : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint)
+            , x(x)
+            , y(y)
+            , radius(radius) {}
+    const float* x;
+    const float* y;
+    const float* radius;
+};
+
 struct LinesOp : RecordedOp {
     LinesOp(BASE_PARAMS, const float* points, const int floatCount)
             : SUPER(LinesOp)
@@ -145,11 +204,68 @@
     const int floatCount;
 };
 
+struct OvalOp : RecordedOp {
+    OvalOp(BASE_PARAMS)
+            : SUPER(OvalOp) {}
+};
+
+struct PatchOp : RecordedOp {
+    PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch)
+            : SUPER(PatchOp)
+            , bitmap(bitmap)
+            , patch(patch) {}
+    const SkBitmap* bitmap;
+    const Res_png_9patch* patch;
+};
+
+struct PathOp : RecordedOp {
+    PathOp(BASE_PARAMS, const SkPath* path)
+            : SUPER(PathOp)
+            , path(path) {}
+    const SkPath* path;
+};
+
+struct PointsOp : RecordedOp {
+    PointsOp(BASE_PARAMS, const float* points, const int floatCount)
+            : SUPER(PointsOp)
+            , points(points)
+            , floatCount(floatCount) {}
+    const float* points;
+    const int floatCount;
+};
+
 struct RectOp : RecordedOp {
     RectOp(BASE_PARAMS)
             : SUPER(RectOp) {}
 };
 
+struct RoundRectOp : RecordedOp {
+    RoundRectOp(BASE_PARAMS, float rx, float ry)
+            : SUPER(RoundRectOp)
+            , rx(rx)
+            , ry(ry) {}
+    const float rx;
+    const float ry;
+};
+
+struct RoundRectPropsOp : RecordedOp {
+    RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+            float* left, float* top, float* right, float* bottom, float *rx, float *ry)
+            : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint)
+            , left(left)
+            , top(top)
+            , right(right)
+            , bottom(bottom)
+            , rx(rx)
+            , ry(ry) {}
+    const float* left;
+    const float* top;
+    const float* right;
+    const float* bottom;
+    const float* rx;
+    const float* ry;
+};
+
 /**
  * Real-time, dynamic-lit shadow.
  *
@@ -225,7 +341,7 @@
  */
 struct EndLayerOp : RecordedOp {
     EndLayerOp()
-            : RecordedOp(RecordedOpId::EndLayerOp, Rect(0, 0), Matrix4::identity(), Rect(0, 0), nullptr) {}
+            : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), Rect(), nullptr) {}
 };
 
 /**
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index e6020cd..c7b16a1 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -237,26 +237,32 @@
             refPaint(&paint)));
 }
 
+static Rect calcBoundsOfPoints(const float* points, int floatCount) {
+    Rect unmappedBounds(points[0], points[1], points[0], points[1]);
+    for (int i = 2; i < floatCount; i += 2) {
+        unmappedBounds.expandToCover(points[i], points[i + 1]);
+    }
+    return unmappedBounds;
+}
+
 // Geometry
-void RecordingCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) {
+    if (floatCount < 2) return;
+    floatCount &= ~0x1; // round down to nearest two
+
+    addOp(new (alloc()) PointsOp(
+            calcBoundsOfPoints(points, floatCount),
+            *mState.currentSnapshot()->transform,
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
 }
 
 void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) {
     if (floatCount < 4) return;
     floatCount &= ~0x3; // round down to nearest four
 
-    Rect unmappedBounds(points[0], points[1], points[0], points[1]);
-    for (int i = 2; i < floatCount; i += 2) {
-        unmappedBounds.expandToCover(points[i], points[i + 1]);
-    }
-
-    // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
-    // 1.0 stroke, treat 1.0 as minimum.
-    unmappedBounds.outset(std::max(paint.getStrokeWidth(), 1.0f) * 0.5f);
-
     addOp(new (alloc()) LinesOp(
-            unmappedBounds,
+            calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
             mState.getRenderTargetClipBounds(),
             refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
@@ -330,20 +336,80 @@
 }
 void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    addOp(new (alloc()) RoundRectOp(
+            Rect(left, top, right, bottom),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint), rx, ry));
 }
+
+void RecordingCanvas::drawRoundRect(
+        CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+        CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
+        CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
+        CanvasPropertyPaint* paint) {
+    mDisplayList->ref(left);
+    mDisplayList->ref(top);
+    mDisplayList->ref(right);
+    mDisplayList->ref(bottom);
+    mDisplayList->ref(rx);
+    mDisplayList->ref(ry);
+    mDisplayList->ref(paint);
+    refBitmapsInShader(paint->value.getShader());
+    addOp(new (alloc()) RoundRectPropsOp(
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            &paint->value,
+            &left->value, &top->value, &right->value, &bottom->value,
+            &rx->value, &ry->value));
+}
+
 void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    // TODO: move to Canvas.h
+    if (radius <= 0) return;
+    drawOval(x - radius, y - radius, x + radius, y + radius, paint);
 }
+
+void RecordingCanvas::drawCircle(
+        CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+        CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+    mDisplayList->ref(x);
+    mDisplayList->ref(y);
+    mDisplayList->ref(radius);
+    mDisplayList->ref(paint);
+    refBitmapsInShader(paint->value.getShader());
+    addOp(new (alloc()) CirclePropsOp(
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            &paint->value,
+            &x->value, &y->value, &radius->value));
+}
+
+
 void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    addOp(new (alloc()) OvalOp(
+            Rect(left, top, right, bottom),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint)));
 }
+
 void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+    addOp(new (alloc()) ArcOp(
+            Rect(left, top, right, bottom),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint),
+            startAngle, sweepAngle, useCenter));
 }
+
 void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    addOp(new (alloc()) PathOp(
+            Rect(path.getBounds()),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(&paint), refPath(&path)));
 }
 
 // Bitmap-based
@@ -375,6 +441,7 @@
         restore();
     }
 }
+
 void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint) {
@@ -389,17 +456,35 @@
         drawBitmap(&bitmap, paint);
         restore();
     } else {
-        LOG_ALWAYS_FATAL("TODO!");
+        addOp(new (alloc()) BitmapRectOp(
+                Rect(dstLeft, dstTop, dstRight, dstBottom),
+                *(mState.currentSnapshot()->transform),
+                mState.getRenderTargetClipBounds(),
+                refPaint(paint), refBitmap(bitmap),
+                Rect(srcLeft, srcTop, srcRight, srcBottom)));
     }
 }
+
 void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
             const float* vertices, const int* colors, const SkPaint* paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    int vertexCount = (meshWidth + 1) * (meshHeight + 1);
+    addOp(new (alloc()) BitmapMeshOp(
+            calcBoundsOfPoints(vertices, vertexCount * 2),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
+            refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
+            refBuffer<int>(colors, vertexCount))); // 1 color per vertex
 }
-void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+
+void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& patch,
             float dstLeft, float dstTop, float dstRight, float dstBottom,
             const SkPaint* paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    addOp(new (alloc()) PatchOp(
+            Rect(dstLeft, dstTop, dstRight, dstBottom),
+            *(mState.currentSnapshot()->transform),
+            mState.getRenderTargetClipBounds(),
+            refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
 }
 
 // Text
@@ -421,13 +506,12 @@
 
 void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
             float hOffset, float vOffset, const SkPaint& paint) {
-    // NOTE: can't use refPaint() directly, since it forces left alignment
     LOG_ALWAYS_FATAL("TODO!");
 }
 
 void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
     addOp(new (alloc()) BitmapOp(
-            Rect(0, 0, bitmap->width(), bitmap->height()),
+            Rect(bitmap->width(), bitmap->height()),
             *(mState.currentSnapshot()->transform),
             mState.getRenderTargetClipBounds(),
             refPaint(paint), refBitmap(*bitmap)));
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 6d0e9e0..6fbaa8a 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -69,6 +69,17 @@
     virtual GLuint getTargetFbo() const override { return -1; }
 
 // ----------------------------------------------------------------------------
+// HWUI Canvas draw operations
+// ----------------------------------------------------------------------------
+
+    void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+            CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
+            CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
+            CanvasPropertyPaint* paint);
+    void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+            CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
+
+// ----------------------------------------------------------------------------
 // android/graphics/Canvas interface
 // ----------------------------------------------------------------------------
     virtual SkCanvas* asSkCanvas() override;
@@ -140,13 +151,13 @@
         float points[2] = { x, y };
         drawPoints(points, 2, paint);
     }
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) override;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
             const SkPaint& paint) override {
         float points[4] = { startX, startY, stopX, stopY };
         drawLines(points, 4, paint);
     }
-    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) override;
     virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
     virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
     virtual void drawRoundRect(float left, float top, float right, float bottom,
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 4bcd96d..1c544b9 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -120,16 +120,16 @@
 
 class AutoTexture {
 public:
-    AutoTexture(const Texture* texture): mTexture(texture) { }
+    AutoTexture(const Texture* texture)
+            : texture(texture) {}
     ~AutoTexture() {
-        if (mTexture && mTexture->cleanup) {
-            mTexture->deleteTexture();
-            delete mTexture;
+        if (texture && texture->cleanup) {
+            texture->deleteTexture();
+            delete texture;
         }
     }
 
-private:
-    const Texture* mTexture;
+    const Texture *const texture;
 }; // class AutoTexture
 
 }; // namespace uirenderer
diff --git a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
new file mode 100644
index 0000000..5dfb2b4
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+#include "utils/Color.h"
+
+class OpPropAnimation;
+
+static TestScene::Registrar _Shapes(TestScene::Info{
+    "opprops",
+    "A minimal demonstration of CanvasProperty drawing operations.",
+    TestScene::simpleCreateScene<OpPropAnimation>
+});
+
+class OpPropAnimation : public TestScene {
+public:
+    sp<CanvasPropertyPaint> mPaint = new CanvasPropertyPaint(SkPaint());
+
+    sp<CanvasPropertyPrimitive> mRoundRectLeft = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mRoundRectTop = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mRoundRectRight = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mRoundRectBottom = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mRoundRectRx = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mRoundRectRy = new CanvasPropertyPrimitive(0);
+
+    sp<CanvasPropertyPrimitive> mCircleX = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mCircleY = new CanvasPropertyPrimitive(0);
+    sp<CanvasPropertyPrimitive> mCircleRadius = new CanvasPropertyPrimitive(0);
+
+    sp<RenderNode> content;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        content = TestUtils::createNode(0, 0, width, height,
+                [this, width, height](RenderProperties& props, TestCanvas& canvas) {
+            mPaint->value.setAntiAlias(true);
+            mPaint->value.setColor(Color::Blue_500);
+
+            mRoundRectRight->value = width / 2;
+            mRoundRectBottom->value = height / 2;
+
+            mCircleX->value = width * 0.75;
+            mCircleY->value = height * 0.75;
+
+            canvas.drawColor(Color::White, SkXfermode::Mode::kSrcOver_Mode);
+            canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(),
+                    mRoundRectRight.get(), mRoundRectBottom.get(),
+                    mRoundRectRx.get(), mRoundRectRy.get(), mPaint.get());
+            canvas.drawCircle(mCircleX.get(), mCircleY.get(), mCircleRadius.get(), mPaint.get());
+        });
+        canvas.drawRenderNode(content.get());
+    }
+
+    void doFrame(int frameNr) override {
+        float value = (abs((frameNr % 200) - 100)) / 100.0f;
+        mRoundRectRx->value = dp(10) + value * dp(40);
+        mRoundRectRy->value = dp(10) + value * dp(80);
+        mCircleRadius->value = value * dp(200);
+        content->setPropertyFieldsDirty(RenderNode::GENERIC);
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
new file mode 100644
index 0000000..0cba344
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+#include "utils/Color.h"
+
+#include <cstdio>
+
+class ShapeAnimation;
+
+static TestScene::Registrar _Shapes(TestScene::Info{
+    "shapes",
+    "A grid of shape drawing test cases.",
+    TestScene::simpleCreateScene<ShapeAnimation>
+});
+
+class ShapeAnimation : public TestScene {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        card = TestUtils::createNode(0, 0, width, height,
+                [width](RenderProperties& props, TestCanvas& canvas) {
+            std::function<void(TestCanvas&, float, const SkPaint&)> ops[] = {
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
+                },
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    canvas.drawOval(0, 0, size, size, paint);
+                },
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    SkPath diamondPath;
+                    diamondPath.moveTo(size / 2, 0);
+                    diamondPath.lineTo(size, size / 2);
+                    diamondPath.lineTo(size / 2, size);
+                    diamondPath.lineTo(0, size / 2);
+                    diamondPath.close();
+                    canvas.drawPath(diamondPath, paint);
+                },
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    float data[] = {0, 0, size, size, 0, size, size, 0 };
+                    canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
+                },
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    float data[] = {0, 0, size, size, 0, size, size, 0 };
+                    canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
+                },
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    canvas.drawRect(0, 0, size, size, paint);
+                },
+                [](TestCanvas& canvas, float size, const SkPaint& paint) {
+                    float rad = size / 4;
+                    canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
+                }
+            };
+            float cellSpace = dp(4);
+            float cellSize = floorf(width / 7 - cellSpace);
+
+            // each combination of strokeWidth + style gets a column
+            int outerCount = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            SkPaint::Style styles[] = {
+                    SkPaint::kStroke_Style, SkPaint::kFill_Style, SkPaint::kStrokeAndFill_Style };
+            for (auto style : styles) {
+                paint.setStyle(style);
+                for (auto strokeWidth : { 0.0f, 0.5f, 8.0f }) {
+                    paint.setStrokeWidth(strokeWidth);
+                    // fill column with each op
+                    int middleCount = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+                    for (auto op : ops) {
+                        int innerCount = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+                        canvas.clipRect(0, 0, cellSize, cellSize, SkRegion::kIntersect_Op);
+                        canvas.drawColor(Color::White, SkXfermode::Mode::kSrcOver_Mode);
+                        op(canvas, cellSize, paint);
+                        canvas.restoreToCount(innerCount);
+                        canvas.translate(cellSize + cellSpace, 0);
+                    }
+                    canvas.restoreToCount(middleCount);
+                    canvas.translate(0, cellSize + cellSpace);
+                }
+            }
+            canvas.restoreToCount(outerCount);
+        });
+        canvas.drawColor(Color::Grey_500, SkXfermode::Mode::kSrcOver_Mode);
+        canvas.drawRenderNode(card.get());
+    }
+
+    void doFrame(int frameNr) override {
+        card->mutateStagingProperties().setTranslationY(frameNr % 150);
+        card->setPropertyFieldsDirty(RenderNode::Y);
+    }
+};
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index de14abf..33eff5b 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -23,41 +23,130 @@
 namespace android {
 namespace uirenderer {
 
-TEST(ResolvedRenderState, resolution) {
-    Matrix4 identity;
-    identity.loadIdentity();
-
+TEST(ResolvedRenderState, construct) {
     Matrix4 translate10x20;
     translate10x20.loadTranslate(10, 20, 0);
 
     SkPaint paint;
-    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(0, 0, 100, 200), &paint);
+    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(100, 200), &paint);
     {
         // recorded with transform, no parent transform
-        auto parentSnapshot = TestUtils::makeSnapshot(identity, Rect(0, 0, 100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp);
+        auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
         EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
-        EXPECT_EQ(state.clipRect, Rect(0, 0, 100, 200));
-        EXPECT_EQ(state.clippedBounds, Rect(40, 60, 100, 200)); // translated and also clipped
+        EXPECT_EQ(Rect(100, 200), state.clipRect);
+        EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
+        EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
     }
     {
         // recorded with transform and parent transform
-        auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(0, 0, 100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp);
+        auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
+        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
 
         Matrix4 expectedTranslate;
         expectedTranslate.loadTranslate(20, 40, 0);
-        EXPECT_MATRIX_APPROX_EQ(state.transform, expectedTranslate);
+        EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
 
         // intersection of parent & transformed child clip
-        EXPECT_EQ(state.clipRect, Rect(10, 20, 100, 200));
+        EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect);
 
         // translated and also clipped
-        EXPECT_EQ(state.clippedBounds, Rect(50, 80, 100, 200));
+        EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
+        EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
     }
 }
 
-TEST(BakedOpState, constructAndReject) {
+const float HAIRLINE = 0.0f;
+
+// Note: bounds will be conservative, but not precise for non-hairline
+// - use approx bounds checks for these
+const float SEMI_HAIRLINE = 0.3f;
+
+struct StrokeTestCase {
+    float scale;
+    float strokeWidth;
+    const std::function<void(const ResolvedRenderState&)> validator;
+};
+
+const static StrokeTestCase sStrokeTestCases[] = {
+    {
+        1, HAIRLINE, [](const ResolvedRenderState& state) {
+            EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
+        }
+    },
+    {
+        1, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
+            EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
+            EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
+        }
+    },
+    {
+        1, 20, [](const ResolvedRenderState& state) {
+            EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
+        }
+    },
+
+    // 3x3 scale:
+    {
+        3, HAIRLINE, [](const ResolvedRenderState& state) {
+            EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
+            EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
+        }
+    },
+    {
+        3, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
+            EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
+            EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
+        }
+    },
+    {
+        3, 20, [](const ResolvedRenderState& state) {
+            EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
+            EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
+        }
+    },
+
+    // 0.5f x 0.5f scale
+    {
+        0.5f, HAIRLINE, [](const ResolvedRenderState& state) {
+            EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
+        }
+    },
+    {
+        0.5f, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
+            EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
+            EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
+        }
+    },
+    {
+        0.5f, 20, [](const ResolvedRenderState& state) {
+            EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
+            EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
+        }
+    }
+};
+
+TEST(ResolvedRenderState, construct_expandForStroke) {
+    // Loop over table of test cases and verify different combinations of stroke width and transform
+    for (auto&& testCase : sStrokeTestCases) {
+        SkPaint strokedPaint;
+        strokedPaint.setAntiAlias(true);
+        strokedPaint.setStyle(SkPaint::kStroke_Style);
+        strokedPaint.setStrokeWidth(testCase.strokeWidth);
+
+        RectOp recordedOp(Rect(50, 50, 150, 150),
+                Matrix4::identity(), Rect(200, 200), &strokedPaint);
+
+        Matrix4 snapshotMatrix;
+        snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
+        auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
+
+        ResolvedRenderState state(*parentSnapshot, recordedOp, true);
+        testCase.validator(state);
+    }
+}
+
+TEST(BakedOpState, tryConstruct) {
     LinearAllocator allocator;
 
     Matrix4 translate100x0;
@@ -65,41 +154,85 @@
 
     SkPaint paint;
     {
-        RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(0, 0, 100, 200), &paint);
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 200));
-        BakedOpState* bakedOp = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
+        RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+        BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
 
-        EXPECT_EQ(bakedOp, nullptr); // rejected by clip, so not constructed
-        EXPECT_LE(allocator.usedSize(), 8u); // no significant allocation space used for rejected op
+        EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
+        EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
     }
     {
-        RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(0, 0, 100, 200), &paint);
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 200));
-        BakedOpState* bakedOp = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
+        RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+        BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
 
-        EXPECT_NE(bakedOp, nullptr); // NOT rejected by clip, so will be constructed
-        EXPECT_GT(allocator.usedSize(), 64u); // relatively large alloc for non-rejected op
+        EXPECT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
+        EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
     }
 }
 
-TEST(BakedOpState, oplessConstructAndReject) {
+TEST(BakedOpState, tryShadowOpConstruct) {
     LinearAllocator allocator;
     {
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 0, 0)); // empty
-        BakedOpState* bakedOp = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
+        BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
 
-        EXPECT_EQ(bakedOp, nullptr); // rejected by clip, so not constructed
-        EXPECT_LE(allocator.usedSize(), 8u); // no significant allocation space used for rejected op
+        EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
+        EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
     }
     {
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 200));
-        BakedOpState* bakedOp = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+        BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
 
-        EXPECT_NE(bakedOp, nullptr); // NOT rejected by clip, so will be constructed
-        EXPECT_GT(allocator.usedSize(), 64u); // relatively large alloc for non-rejected op
-        EXPECT_EQ((ShadowOp*)0x1234, bakedOp->op);
+        ASSERT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
+        EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
     }
 }
 
+TEST(BakedOpState, tryStrokeableOpConstruct) {
+    LinearAllocator allocator;
+    {
+        // check regular rejection
+        SkPaint paint;
+        paint.setStyle(SkPaint::kStrokeAndFill_Style);
+        paint.setStrokeWidth(0.0f);
+        RectOp rejectOp(Rect(100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
+        auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
+                BakedOpState::StrokeBehavior::StyleDefined);
+
+        EXPECT_EQ(nullptr, bakedState);
+        EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
+    }
+    {
+        // check simple unscaled expansion
+        SkPaint paint;
+        paint.setStyle(SkPaint::kStrokeAndFill_Style);
+        paint.setStrokeWidth(10.0f);
+        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
+        auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
+                BakedOpState::StrokeBehavior::StyleDefined);
+
+        ASSERT_NE(nullptr, bakedState);
+        EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
+        EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
+    }
+    {
+        // check simple unscaled expansion, and fill style with stroke forced
+        SkPaint paint;
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setStrokeWidth(10.0f);
+        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
+        auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
+                BakedOpState::StrokeBehavior::Forced);
+
+        ASSERT_NE(nullptr, bakedState);
+        EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
+        EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
+    }
 }
-}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index dfbf6d3..4df2687 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -57,7 +57,7 @@
     simpleTranslate.loadTranslate(10, 20, 0);
     state.setMatrix(simpleTranslate);
 
-    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200));
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));
     ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
     EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
     EXPECT_TRUE(state.clipIsSimple());
@@ -69,7 +69,7 @@
             0, 0, 200, 200, Vector3());
 
     state.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
-    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 100, 100));
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
 
     state.clipRect(10, 10, 200, 200, SkRegion::kIntersect_Op);
     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
@@ -122,10 +122,10 @@
     state.save(SkCanvas::kClip_SaveFlag);
     {
         state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
-        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
     }
     state.restore();
-    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200)); // verify restore
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
 
     Matrix4 simpleTranslate;
     simpleTranslate.loadTranslate(10, 10, 0);
@@ -146,10 +146,10 @@
     state.save(SkCanvas::kMatrix_SaveFlag); // NOTE: clip not saved
     {
         state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
-        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
     }
     state.restore();
-    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10)); // verify not restored
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
 
     Matrix4 simpleTranslate;
     simpleTranslate.loadTranslate(10, 10, 0);
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index d6192df..c4d305e 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -92,12 +92,10 @@
 
 TEST(ClipArea, paths) {
     ClipArea area(createClipArea());
-    Matrix4 transform;
-    transform.loadIdentity();
     SkPath path;
     SkScalar r = 100;
     path.addCircle(r, r, r);
-    area.clipPathWithTransform(path, &transform, SkRegion::kIntersect_Op);
+    area.clipPathWithTransform(path, &Matrix4::identity(), SkRegion::kIntersect_Op);
     EXPECT_FALSE(area.isEmpty());
     EXPECT_FALSE(area.isSimple());
     EXPECT_FALSE(area.isRectangleList());
@@ -116,11 +114,10 @@
     ClipArea area(createClipArea());
     area.setClip(0, 0, 100, 100);
 
-    Matrix4 transform;
-    transform.loadIdentity();
     Rect expected(-50, -50, 50, 50);
-    area.clipRectWithTransform(expected, &transform, SkRegion::kReplace_Op);
+    area.clipRectWithTransform(expected, &Matrix4::identity(), SkRegion::kReplace_Op);
     EXPECT_EQ(expected, area.getClipRect());
 }
+
 }
 }
diff --git a/libs/hwui/tests/unit/DamageAccumulatorTests.cpp b/libs/hwui/tests/unit/DamageAccumulatorTests.cpp
index 29354a7..7700138 100644
--- a/libs/hwui/tests/unit/DamageAccumulatorTests.cpp
+++ b/libs/hwui/tests/unit/DamageAccumulatorTests.cpp
@@ -31,13 +31,11 @@
 // as the output.
 TEST(DamageAccumulator, identity) {
     DamageAccumulator da;
-    Matrix4 identity;
     SkRect curDirty;
-    identity.loadIdentity();
-    da.pushTransform(&identity);
+    da.pushTransform(&Matrix4::identity());
     da.dirty(50, 50, 100, 100);
     {
-        da.pushTransform(&identity);
+        da.pushTransform(&Matrix4::identity());
         da.peekAtDirty(&curDirty);
         ASSERT_EQ(SkRect(), curDirty);
         da.popTransform();
@@ -68,15 +66,13 @@
 // Test that dirty rectangles are being unioned across "siblings
 TEST(DamageAccumulator, union) {
     DamageAccumulator da;
-    Matrix4 identity;
     SkRect curDirty;
-    identity.loadIdentity();
-    da.pushTransform(&identity);
+    da.pushTransform(&Matrix4::identity());
     {
-        da.pushTransform(&identity);
+        da.pushTransform(&Matrix4::identity());
         da.dirty(50, 50, 100, 100);
         da.popTransform();
-        da.pushTransform(&identity);
+        da.pushTransform(&Matrix4::identity());
         da.dirty(150, 50, 200, 125);
         da.popTransform();
     }
diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp
index 068e832..ac356a47 100644
--- a/libs/hwui/tests/unit/OpReordererTests.cpp
+++ b/libs/hwui/tests/unit/OpReordererTests.cpp
@@ -144,6 +144,32 @@
     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
 }
 
+TEST(OpReorderer, simpleStroke) {
+    class SimpleStrokeTestRenderer : public TestRendererBase {
+    public:
+        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            // even though initial bounds are empty...
+            EXPECT_TRUE(op.unmappedBounds.isEmpty())
+                    << "initial bounds should be empty, since they're unstroked";
+            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
+                    << "final bounds should account for stroke";
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 100, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkPaint strokedPaint;
+        strokedPaint.setStrokeWidth(10);
+        canvas.drawPoint(50, 50, strokedPaint);
+    });
+    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+            createSyncedNodeList(node), sLightCenter);
+    SimpleStrokeTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex());
+}
+
 TEST(OpReorderer, simpleRejection) {
     auto node = TestUtils::createNode(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
@@ -233,7 +259,7 @@
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
             switch(mIndex++) {
             case 0:
-                EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
+                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
                 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
                 break;
             case 1:
@@ -311,8 +337,8 @@
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
             EXPECT_EQ(1, mIndex++);
             EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
-            EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
+            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
+            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect);
 
             Matrix4 expectedTransform;
             expectedTransform.loadTranslate(-10, -10, 0);
@@ -321,7 +347,7 @@
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(3, mIndex++);
             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect);
             EXPECT_TRUE(state.computedState.transform.isIdentity());
         }
     };
@@ -373,19 +399,19 @@
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
             const int index = mIndex++;
             if (index == 1) {
-                EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
+                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
             } else if (index == 4) {
-                EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
+                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
             } else { ADD_FAILURE(); }
         }
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             const int index = mIndex++;
             if (index == 5) {
                 EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
-                EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
+                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
             } else if (index == 8) {
                 EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
-                EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
+                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
             } else { ADD_FAILURE(); }
         }
     };
@@ -1065,7 +1091,7 @@
     });
     EXPECT_EQ(190u, observedData.layerWidth);
     EXPECT_EQ(200u, observedData.layerHeight);
-    EXPECT_EQ(Rect(0, 0, 190, 200), observedData.rectClippedBounds)
+    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
             << "expect content to be clipped to screen area";
     Matrix4 expected;
     expected.loadTranslate(0, -2000, 0);
@@ -1088,7 +1114,7 @@
     // ceil(sqrt(2) / 2 * 200) = 142
     EXPECT_EQ(142u, observedData.layerWidth);
     EXPECT_EQ(142u, observedData.layerHeight);
-    EXPECT_EQ(Rect(0, 0, 142, 142), observedData.rectClippedBounds);
+    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
@@ -1102,7 +1128,7 @@
     });
     EXPECT_EQ(100u, observedData.layerWidth);
     EXPECT_EQ(400u, observedData.layerHeight);
-    EXPECT_EQ(Rect(0, 0, 100, 400), observedData.rectClippedBounds);
+    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 2449ce8..08f927c 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -44,7 +44,7 @@
 TEST(RecordingCanvas, drawLines) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
-        paint.setStrokeWidth(20);
+        paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
         float points[] = { 0, 0, 20, 10, 30, 40, 90 }; // NB: only 1 valid line
         canvas.drawLines(&points[0], 7, paint);
     });
@@ -54,8 +54,8 @@
     ASSERT_EQ(RecordedOpId::LinesOp, op->opId);
     EXPECT_EQ(4, ((LinesOp*)op)->floatCount)
             << "float count must be rounded down to closest multiple of 4";
-    EXPECT_EQ(Rect(-10, -10, 30, 20), op->unmappedBounds)
-            << "unmapped bounds must be size of line, outset by 1/2 stroke width";
+    EXPECT_EQ(Rect(20, 10), op->unmappedBounds)
+            << "unmapped bounds must be size of line, and not outset for stroke width";
 }
 
 TEST(RecordingCanvas, drawRect) {
@@ -66,7 +66,7 @@
     ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
     auto op = *(dl->getOps()[0]);
     ASSERT_EQ(RecordedOpId::RectOp, op.opId);
-    EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+    EXPECT_EQ(Rect(100, 200), op.localClipRect);
     EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
 }
 
@@ -83,7 +83,7 @@
     playbackOps(*dl, [&count](const RecordedOp& op) {
         count++;
         ASSERT_EQ(RecordedOpId::TextOp, op.opId);
-        EXPECT_EQ(Rect(0, 0, 200, 200), op.localClipRect);
+        EXPECT_EQ(Rect(200, 200), op.localClipRect);
         EXPECT_TRUE(op.localMatrix.isIdentity());
         EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
                 << "Op expected to be 25+ pixels wide, 10+ pixels tall";
@@ -184,8 +184,8 @@
             ASSERT_EQ(RecordedOpId::RectOp, op.opId);
             ASSERT_NE(nullptr, op.paint);
             EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
-            EXPECT_EQ(Rect(0, 0, 100, 200), op.unmappedBounds);
-            EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+            EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
+            EXPECT_EQ(Rect(100, 200), op.localClipRect);
 
             Matrix4 expectedMatrix;
             expectedMatrix.loadIdentity();
@@ -193,8 +193,8 @@
         } else {
             ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
             EXPECT_EQ(nullptr, op.paint);
-            EXPECT_EQ(Rect(0, 0, 25, 25), op.unmappedBounds);
-            EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+            EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
+            EXPECT_EQ(Rect(100, 200), op.localClipRect);
 
             Matrix4 expectedMatrix;
             expectedMatrix.loadTranslate(25, 25, 0);
@@ -219,12 +219,12 @@
         case 0:
             EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
             EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
-            EXPECT_EQ(Rect(0, 0, 200, 200), op.localClipRect);
+            EXPECT_EQ(Rect(200, 200), op.localClipRect);
             EXPECT_TRUE(op.localMatrix.isIdentity());
             break;
         case 1:
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(0, 0, 180, 160), op.localClipRect);
+            EXPECT_EQ(Rect(180, 160), op.localClipRect);
             EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
             expectedMatrix.loadTranslate(-10, -20, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -254,9 +254,9 @@
         if (count++ == 1) {
             Matrix4 expectedMatrix;
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect) << "Recorded clip rect should be"
+            EXPECT_EQ(Rect(100, 100), op.localClipRect) << "Recorded clip rect should be"
                     " intersection of viewport and saveLayer bounds, in layer space";
-            EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
+            EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadTranslate(-100, -100, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
         }
@@ -281,8 +281,8 @@
     playbackOps(*dl, [&count](const RecordedOp& op) {
         if (count++ == 1) {
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect);
-            EXPECT_EQ(Rect(0, 0, 100, 100), op.unmappedBounds);
+            EXPECT_EQ(Rect(100, 100), op.localClipRect);
+            EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
             EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
                     << "Recorded op shouldn't see any canvas transform before the saveLayer";
         }
@@ -313,7 +313,7 @@
             // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
             // the parent 200x200 viewport, but prior to rotation
             EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), op.localClipRect);
-            EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
+            EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadIdentity();
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
         }
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
index 6895f07..06bcdcd 100644
--- a/libs/hwui/utils/RingBuffer.h
+++ b/libs/hwui/utils/RingBuffer.h
@@ -32,7 +32,7 @@
     ~RingBuffer() {}
 
     constexpr size_t capacity() const { return SIZE; }
-    size_t size() { return mCount; }
+    size_t size() const { return mCount; }
 
     T& next() {
         mHead = (mHead + 1) % SIZE;
@@ -54,6 +54,10 @@
         return mBuffer[(mHead + index + 1) % mCount];
     }
 
+    const T& operator[](size_t index) const {
+        return mBuffer[(mHead + index + 1) % mCount];
+    }
+
     void clear() {
         mCount = 0;
         mHead = -1;
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 84aae75..05b4a72 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -180,6 +180,10 @@
 TestWindowContext::TestWindowContext() :
     mData (nullptr) { }
 
+TestWindowContext::~TestWindowContext() {
+    delete mData;
+}
+
 void TestWindowContext::initialize(int width, int height)  {
     mData = new TestWindowData(SkISize::Make(width, height));
 }
diff --git a/libs/hwui/utils/TestWindowContext.h b/libs/hwui/utils/TestWindowContext.h
index 445a11b..48ec952 100644
--- a/libs/hwui/utils/TestWindowContext.h
+++ b/libs/hwui/utils/TestWindowContext.h
@@ -35,6 +35,7 @@
 public:
 
     TestWindowContext();
+    ~TestWindowContext();
 
     /// We need to know the size of the window.
     void initialize(int width, int height);
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 6a1167a..529849e 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -439,6 +439,17 @@
     }
 }
 
+void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
+    AutoMutex _l(mLock);
+
+    const int32_t iconId = mPolicy->getCustomPointerIconId();
+    mLocked.additionalMouseResources[iconId] = icon;
+    mLocked.requestedPointerShape = iconId;
+    mLocked.presentationChanged = true;
+
+    updatePointerLocked();
+}
+
 void PointerController::handleMessage(const Message& message) {
     switch (message.what) {
     case MSG_INACTIVITY_TIMEOUT:
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 4fd2d85..9ba37b3 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -67,6 +67,7 @@
     virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
             std::map<int32_t, PointerAnimation>* outAnimationResources) = 0;
     virtual int32_t getDefaultPointerIconId() = 0;
+    virtual int32_t getCustomPointerIconId() = 0;
 };
 
 
@@ -105,6 +106,7 @@
     virtual void clearSpots();
 
     void updatePointerShape(int32_t iconId);
+    void setCustomPointerIcon(const SpriteIcon& icon);
     void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
     void reloadPointerResources();
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 045216b..3e75759 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -141,6 +141,16 @@
      *     {@link android.hardware.camera2.CameraDevice CameraDevice}.
      *   </td>
      * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#RAW_PRIVATE RAW_PRIVATE}</td>
+     *   <td>1</td>
+     *   <td>A single plane of raw sensor image data of private layout.
+     *   The details of the layout is implementation specific. Row stride and
+     *   pixel stride are undefined for this format. Calling {@link Plane#getRowStride()}
+     *   or {@link Plane#getPixelStride()} on RAW_PRIVATE image will cause
+     *   UnSupportedOperationException being thrown.
+     *   </td>
+     * </tr>
      * </table>
      *
      * @see android.graphics.ImageFormat
@@ -341,7 +351,13 @@
          * <p>The row stride for this color plane, in bytes.</p>
          *
          * <p>This is the distance between the start of two consecutive rows of
-         * pixels in the image. The row stride is always greater than 0.</p>
+         * pixels in the image. Note that row stried is undefined for some formats
+         * such as
+         * {@link android.graphics.ImageFormat#RAW_PRIVATE RAW_PRIVATE},
+         * and calling getRowStride on images of these formats will
+         * cause an UnsupportedOperationException being thrown.
+         * For formats where row stride is well defined, the row stride
+         * is always greater than 0.</p>
          */
         public abstract int getRowStride();
         /**
@@ -350,7 +366,12 @@
          * <p>This is the distance between two consecutive pixel values in a row
          * of pixels. It may be larger than the size of a single pixel to
          * account for interleaved image data or padded formats.
-         * The pixel stride is always greater than 0.</p>
+         * Note that pixel stride is undefined for some formats such as
+         * {@link android.graphics.ImageFormat#RAW_PRIVATE RAW_PRIVATE},
+         * and calling getPixelStride on images of these formats will
+         * cause an UnsupportedOperationException being thrown.
+         * For formats where pixel stride is well defined, the pixel stride
+         * is always greater than 0.</p>
          */
         public abstract int getPixelStride();
         /**
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 66a174c..397ab15 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -570,7 +570,7 @@
 
         nativeDetachImage(image);
         si.setDetached(true);
-   }
+    }
 
     private boolean isImageOwnedbyMe(Image image) {
         if (!(image instanceof SurfaceImage)) {
@@ -675,6 +675,7 @@
             switch(getFormat()) {
                 case ImageFormat.JPEG:
                 case ImageFormat.DEPTH_POINT_CLOUD:
+                case ImageFormat.RAW_PRIVATE:
                     width = ImageReader.this.getWidth();
                     break;
                 default:
@@ -690,6 +691,7 @@
             switch(getFormat()) {
                 case ImageFormat.JPEG:
                 case ImageFormat.DEPTH_POINT_CLOUD:
+                case ImageFormat.RAW_PRIVATE:
                     height = ImageReader.this.getHeight();
                     break;
                 default:
@@ -791,12 +793,20 @@
             @Override
             public int getPixelStride() {
                 SurfaceImage.this.throwISEIfImageIsInvalid();
+                if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
+                    throw new UnsupportedOperationException(
+                            "getPixelStride is not supported for RAW_PRIVATE plane");
+                }
                 return mPixelStride;
             }
 
             @Override
             public int getRowStride() {
                 SurfaceImage.this.throwISEIfImageIsInvalid();
+                if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
+                    throw new UnsupportedOperationException(
+                            "getRowStride is not supported for RAW_PRIVATE plane");
+                }
                 return mRowStride;
             }
 
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index eefd69c..abf6b20 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -57,6 +57,7 @@
             case ImageFormat.Y8:
             case ImageFormat.Y16:
             case ImageFormat.RAW_SENSOR:
+            case ImageFormat.RAW_PRIVATE:
             case ImageFormat.RAW10:
             case ImageFormat.RAW12:
             case ImageFormat.DEPTH16:
@@ -98,6 +99,10 @@
                 dst.getFormat() == ImageFormat.PRIVATE) {
             throw new IllegalArgumentException("PRIVATE format images are not copyable");
         }
+        if (src.getFormat() == ImageFormat.RAW_PRIVATE) {
+            throw new IllegalArgumentException(
+                    "Copy of RAW_OPAQUE format has not been implemented");
+        }
         if (!(dst.getOwner() instanceof ImageWriter)) {
             throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"
                     + " the images from ImageWriter are writable");
@@ -193,7 +198,8 @@
             case ImageFormat.YV12:
             case ImageFormat.YUV_420_888:
             case ImageFormat.NV21:
-            case ImageFormat.PRIVATE: // A really rough estimate because the real size is unknown.
+            case ImageFormat.RAW12:
+            case ImageFormat.PRIVATE: // A rough estimate because the real size is unknown.
                 estimatedBytePerPixel = 1.5;
                 break;
             case ImageFormat.NV16:
@@ -201,6 +207,7 @@
             case ImageFormat.YUY2:
             case ImageFormat.Y16:
             case ImageFormat.RAW_SENSOR:
+            case ImageFormat.RAW_PRIVATE: // round estimate, real size is unknown
             case ImageFormat.DEPTH16:
                 estimatedBytePerPixel = 2.0;
                 break;
@@ -245,6 +252,7 @@
             case ImageFormat.Y16:
             case ImageFormat.RAW_SENSOR:
             case ImageFormat.RAW10:
+            case ImageFormat.RAW12:
                 return new Size(image.getWidth(), image.getHeight());
             case ImageFormat.PRIVATE:
                 return new Size(0, 0);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4101935..e6bc8f1 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1735,7 +1735,8 @@
             CodecProfileLevel[] profileLevels = mParent.profileLevels;
             String mime = mParent.getMimeType();
 
-            if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+            if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC) ||
+                    mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_DOLBY_AVC)) {
                 maxBlocks = 99;
                 maxBlocksPerSecond = 1485;
                 maxBps = 64000;
@@ -2089,7 +2090,8 @@
                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
                         1 /* widthAlignment */, 1 /* heightAlignment */);
-            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC) ||
+                    mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_DOLBY_HEVC)) {
                 maxBlocks = 36864;
                 maxBlocksPerSecond = maxBlocks * 15;
                 maxBps = 128000;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index b2fa0ac..a102e51 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -92,6 +92,8 @@
     public static final String MIMETYPE_VIDEO_H263 = "video/3gpp";
     public static final String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
     public static final String MIMETYPE_VIDEO_RAW = "video/raw";
+    public static final String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
+    public static final String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
 
     public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
     public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index a046512..bcc2b406 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
@@ -41,6 +42,8 @@
 import android.util.Log;
 import android.view.Display;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -201,6 +204,7 @@
                         info.mDescription = sStatic.mResources.getText(
                                 com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
                         info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
+                        info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH;
                         sStatic.mBluetoothA2dpRoute = info;
                         addRouteStatic(sStatic.mBluetoothA2dpRoute);
                     } else {
@@ -480,6 +484,7 @@
             route.mName = globalRoute.name;
             route.mDescription = globalRoute.description;
             route.mSupportedTypes = globalRoute.supportedTypes;
+            route.mDeviceType = globalRoute.deviceType;
             route.mEnabled = globalRoute.enabled;
             route.setRealStatusCode(globalRoute.statusCode);
             route.mPlaybackType = globalRoute.playbackType;
@@ -1411,6 +1416,7 @@
         newRoute.mDescription = sStatic.mResources.getText(
                 com.android.internal.R.string.wireless_display_route_description);
         newRoute.updatePresentationDisplay();
+        newRoute.mDeviceType = RouteInfo.DEVICE_TYPE_TV;
         return newRoute;
     }
 
@@ -1470,6 +1476,7 @@
         CharSequence mDescription;
         private CharSequence mStatus;
         int mSupportedTypes;
+        int mDeviceType;
         RouteGroup mGroup;
         final RouteCategory mCategory;
         Drawable mIcon;
@@ -1502,6 +1509,42 @@
         /** @hide */ public static final int STATUS_IN_USE = 5;
         /** @hide */ public static final int STATUS_CONNECTED = 6;
 
+        /** @hide */
+        @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface DeviceType {}
+
+        /**
+         * The default receiver device type of the route indicating the type is unknown.
+         *
+         * @see #getDeviceType
+         */
+        public static final int DEVICE_TYPE_UNKNOWN = 0;
+
+        /**
+         * A receiver device type of the route indicating the presentation of the media is happening
+         * on a TV.
+         *
+         * @see #getDeviceType
+         */
+        public static final int DEVICE_TYPE_TV = 1;
+
+        /**
+         * A receiver device type of the route indicating the presentation of the media is happening
+         * on a speaker.
+         *
+         * @see #getDeviceType
+         */
+        public static final int DEVICE_TYPE_SPEAKER = 2;
+
+        /**
+         * A receiver device type of the route indicating the presentation of the media is happening
+         * on a bluetooth device such as a bluetooth speaker.
+         *
+         * @see #getDeviceType
+         */
+        public static final int DEVICE_TYPE_BLUETOOTH = 3;
+
         private Object mTag;
 
         /**
@@ -1533,6 +1576,7 @@
 
         RouteInfo(RouteCategory category) {
             mCategory = category;
+            mDeviceType = DEVICE_TYPE_UNKNOWN;
         }
 
         /**
@@ -1670,6 +1714,18 @@
             return mSupportedTypes;
         }
 
+        /**
+         * Gets the type of the receiver device associated with this route.
+         *
+         * @return The type of the receiver device associated with this route:
+         * {@link #DEVICE_TYPE_BLUETOOTH}, {@link #DEVICE_TYPE_TV}, {@link #DEVICE_TYPE_SPEAKER},
+         * or {@link #DEVICE_TYPE_UNKNOWN}.
+         */
+        @DeviceType
+        public int getDeviceType() {
+            return mDeviceType;
+        }
+
         /** @hide */
         public boolean matchesTypes(int types) {
             return (mSupportedTypes & types) != 0;
diff --git a/media/java/android/media/MediaRouterClientState.java b/media/java/android/media/MediaRouterClientState.java
index 54b8276..34e18f6 100644
--- a/media/java/android/media/MediaRouterClientState.java
+++ b/media/java/android/media/MediaRouterClientState.java
@@ -104,6 +104,7 @@
         public int volumeMax;
         public int volumeHandling;
         public int presentationDisplayId;
+        public @MediaRouter.RouteInfo.DeviceType int deviceType;
 
         public RouteInfo(String id) {
             this.id = id;
@@ -113,6 +114,7 @@
             playbackStream = -1;
             volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
             presentationDisplayId = -1;
+            deviceType = MediaRouter.RouteInfo.DEVICE_TYPE_UNKNOWN;
         }
 
         public RouteInfo(RouteInfo other) {
@@ -128,6 +130,7 @@
             volumeMax = other.volumeMax;
             volumeHandling = other.volumeHandling;
             presentationDisplayId = other.presentationDisplayId;
+            deviceType = other.deviceType;
         }
 
         RouteInfo(Parcel in) {
@@ -143,6 +146,7 @@
             volumeMax = in.readInt();
             volumeHandling = in.readInt();
             presentationDisplayId = in.readInt();
+            deviceType = in.readInt();
         }
 
         @Override
@@ -164,6 +168,7 @@
             dest.writeInt(volumeMax);
             dest.writeInt(volumeHandling);
             dest.writeInt(presentationDisplayId);
+            dest.writeInt(deviceType);
         }
 
         @Override
@@ -180,6 +185,7 @@
                     + ", volumeMax=" + volumeMax
                     + ", volumeHandling=" + volumeHandling
                     + ", presentationDisplayId=" + presentationDisplayId
+                    + ", deviceType=" + deviceType
                     + " }";
         }
 
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 9a53186..1c043e0 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -101,6 +101,8 @@
     void setOpaqueConsumer(const sp<BufferItemConsumer>& consumer) { mOpaqueConsumer = consumer; }
     BufferItemConsumer* getOpaqueConsumer() { return mOpaqueConsumer.get(); }
     // This is the only opaque format exposed in the ImageFormat public API.
+    // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
+    // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
     bool isOpaque() { return mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; }
 
     void setProducer(const sp<IGraphicBufferProducer>& producer) { mProducer = producer; }
@@ -470,7 +472,8 @@
         case HAL_PIXEL_FORMAT_BLOB:
             // Used for JPEG data, height must be 1, width == size, single plane.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);
+            ALOG_ASSERT(buffer->height == 1,
+                    "JPEG should has height value one but got %d", buffer->height);
 
             pData = buffer->data;
             dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
@@ -482,6 +485,14 @@
             pData = buffer->data;
             dataSize = buffer->stride * buffer->height * bytesPerPixel;
             break;
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            ALOG_ASSERT(buffer->height == 1,
+                    "RAW_PRIVATE should has height value one but got %d", buffer->height);
+            pData = buffer->data;
+            dataSize = buffer->width;
+            break;
         case HAL_PIXEL_FORMAT_RAW10:
             // Single plane 10bpp bayer data.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -593,6 +604,10 @@
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
             pixelStride = 3;
             break;
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            pixelStride = 0; // RAW OPAQUE doesn't have pixel stride
+            break;
         default:
             jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
                                  "Pixel format: 0x%x is unsupported", fmt);
@@ -669,6 +684,10 @@
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
             rowStride = buffer->stride * 3;
             break;
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+            rowStride = 0; // RAW OPAQUE doesn't have row stride
+            break;
         default:
             ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
             jniThrowException(env, "java/lang/UnsupportedOperationException",
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 57969ba..6f74203 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -129,7 +129,7 @@
 
             int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
 
-            if (res != CameraBinderTestUtils.NO_ERROR && res != CameraBinderTestUtils.EOPNOTSUPP) {
+            if (res != CameraBinderTestUtils.NO_ERROR && res != -android.system.OsConstants.EOPNOTSUPP) {
                 fail("Camera service returned bad value when queried if it supports camera2 api: "
                         + res + " for camera ID " + cameraId);
             }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
index 6be538a..5c4b23b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -2,6 +2,7 @@
 package com.android.mediaframeworktest.integration;
 
 import static org.junit.Assert.assertNotNull;
+import static android.system.OsConstants.*;
 
 import android.content.Context;
 import android.content.pm.FeatureInfo;
@@ -18,11 +19,10 @@
     static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
 
     protected static final int USE_CALLING_UID = -1;
-    protected static final int BAD_VALUE = -22;
-    protected static final int INVALID_OPERATION = -38;
-    protected static final int ALREADY_EXISTS = -17;
+    protected static final int BAD_VALUE = -EINVAL;
+    protected static final int INVALID_OPERATION = -ENOSYS;
+    protected static final int ALREADY_EXISTS = -EEXIST;
     public static final int NO_ERROR = 0;
-    public static final int EOPNOTSUPP = -95;
     private final Context mContext;
 
     public CameraBinderTestUtils(Context context) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
index 727af78..33c6388 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.*;
 import static android.hardware.camera2.utils.CameraBinderDecorator.*;
 import static android.hardware.camera2.CameraAccessException.*;
+import static android.system.OsConstants.*;
 
 import junit.framework.Assert;
 
@@ -78,9 +79,9 @@
             when(mock.doSomethingAlreadyExists()).thenReturn(ALREADY_EXISTS);
             when(mock.doSomethingBadValue()).thenReturn(BAD_VALUE);
             when(mock.doSomethingDeadObject()).thenReturn(DEAD_OBJECT);
-            when(mock.doSomethingBadPolicy()).thenReturn(EACCES);
-            when(mock.doSomethingDeviceBusy()).thenReturn(EBUSY);
-            when(mock.doSomethingNoSuchDevice()).thenReturn(ENODEV);
+            when(mock.doSomethingBadPolicy()).thenReturn(-EACCES);
+            when(mock.doSomethingDeviceBusy()).thenReturn(-EBUSY);
+            when(mock.doSomethingNoSuchDevice()).thenReturn(-ENODEV);
             when(mock.doSomethingUnknownErrorCode()).thenReturn(SOME_ARBITRARY_NEGATIVE_INT);
             when(mock.doSomethingThrowDeadObjectException()).thenThrow(new DeadObjectException());
             when(mock.doSomethingThrowTransactionTooLargeException()).thenThrow(
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index aecf542..6172c77 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="2783841764617238354">"Документтер"</string>
     <string name="files_label" msgid="6051402950202690279">"Файлдар"</string>
-    <string name="downloads_label" msgid="959113951084633612">"Жүктөөлөр"</string>
+    <string name="downloads_label" msgid="959113951084633612">"Жүктөлүп алынгандар"</string>
     <string name="title_open" msgid="4353228937663917801">"Кийинкиден ачуу:"</string>
     <string name="title_save" msgid="2433679664882857999">"Кийинкиге сактоо:"</string>
     <string name="menu_create_dir" msgid="2547620241173881754">"Жаңы куржун"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index b944736..1b5ace4 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="2783841764617238354">"Hujjatlar"</string>
     <string name="files_label" msgid="6051402950202690279">"Fayllar"</string>
-    <string name="downloads_label" msgid="959113951084633612">"Yuklanmalar"</string>
+    <string name="downloads_label" msgid="959113951084633612">"Yuklanishlar"</string>
     <string name="title_open" msgid="4353228937663917801">"Ochish"</string>
     <string name="title_save" msgid="2433679664882857999">"Saqlash"</string>
     <string name="menu_create_dir" msgid="2547620241173881754">"Yangi jild"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index b99c806..6d947d1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -28,6 +28,7 @@
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
@@ -170,8 +171,27 @@
 
             setupCopyJob(srcs, stack, transferMode);
 
+            final String opDesc = transferMode == TRANSFER_MODE_COPY ? "copy" : "move";
+            DocumentInfo srcInfo;
+            DocumentInfo dstInfo;
             for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
-                copy(srcs.get(i), stack.peek(), transferMode);
+                srcInfo = srcs.get(i);
+                dstInfo = stack.peek();
+
+                // Guard unsupported recursive operation.
+                if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
+                    if (DEBUG) Log.d(TAG,
+                            "Skipping recursive " + opDesc + " of directory " + dstInfo.derivedUri);
+                    mFailedFiles.add(srcInfo);
+                    continue;
+                }
+
+                if (DEBUG) Log.d(TAG,
+                        "Performing " + opDesc + " of " + srcInfo.displayName
+                        + " (" + srcInfo.derivedUri + ")" + " to " + dstInfo.displayName
+                        + " (" + dstInfo.derivedUri + ")");
+
+                copy(srcInfo, dstInfo, transferMode);
             }
         } catch (Exception e) {
             // Catch-all to prevent any copy errors from wedging the app.
@@ -447,22 +467,6 @@
      */
     private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
             throws RemoteException {
-
-        String opDesc = mode == TRANSFER_MODE_COPY ? "copy" : "move";
-
-        // Guard unsupported recursive operation.
-        if (dstDirInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstDirInfo)) {
-            if (DEBUG) Log.d(TAG,
-                    "Skipping recursive " + opDesc + " of directory " + dstDirInfo.derivedUri);
-            mFailedFiles.add(srcInfo);
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG,
-                "Performing " + opDesc + " of " + srcInfo.displayName
-                + " (" + srcInfo.derivedUri + ")" + " to " + dstDirInfo.displayName
-                + " (" + dstDirInfo.derivedUri + ")");
-
         // When copying within the same provider, try to use optimized copying and moving.
         // If not supported, then fallback to byte-by-byte copy/move.
         if (srcInfo.authority.equals(dstDirInfo.authority)) {
@@ -490,6 +494,8 @@
             }
         }
 
+        // Create the target document (either a file or a directory), then copy recursively the
+        // contents (bytes or children).
         final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
                 srcInfo.mimeType, srcInfo.displayName);
         if (dstUri == null) {
@@ -498,10 +504,30 @@
             return;
         }
 
-        if (srcInfo.isDirectory()) {
-            copyDirectoryHelper(srcInfo.derivedUri, dstUri, mode);
+        DocumentInfo dstInfo = null;
+        try {
+            final DocumentInfo dstDocInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
+        } catch (FileNotFoundException e) {
+            mFailedFiles.add(srcInfo);
+            return;
+        }
+
+        if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) {
+            copyDirectoryHelper(srcInfo, dstInfo, mode);
         } else {
-            copyFileHelper(srcInfo.derivedUri, dstUri, mode);
+            copyFileHelper(srcInfo, dstInfo, mode);
+        }
+
+        if (mode == TRANSFER_MODE_MOVE) {
+            try {
+                DocumentsContract.deleteDocument(mSrcClient, srcInfo.derivedUri);
+            } catch (RemoteException e) {
+                // RemoteExceptions usually signal that the connection is dead, so there's no
+                // point attempting to continue. Propagate the exception up so the copy job is
+                // cancelled.
+                Log.w(TAG, "Failed to clean up after move: " + srcInfo.derivedUri, e);
+                throw e;
+            }
         }
     }
 
@@ -520,48 +546,29 @@
      * Handles recursion into a directory and copying its contents. Note that in linux terms, this
      * does the equivalent of "cp src/* dst", not "cp -r src dst".
      *
-     * @param srcDirUri URI of the directory to copy from. The routine will copy the directory's
+     * @param srcDirInfo Info of the directory to copy from. The routine will copy the directory's
      *            contents, not the directory itself.
-     * @param dstDirUri URI of the directory to copy to. Must be created beforehand.
+     * @param dstDirInfo Info of the directory to copy to. Must be created beforehand.
      * @throws RemoteException
      */
-    private void copyDirectoryHelper(Uri srcDirUri, Uri dstDirUri, int mode)
+    private void copyDirectoryHelper(DocumentInfo srcDirInfo, DocumentInfo dstDirInfo, int mode)
             throws RemoteException {
         // Recurse into directories. Copy children into the new subdirectory.
         final String queryColumns[] = new String[] {
                 Document.COLUMN_DISPLAY_NAME,
                 Document.COLUMN_DOCUMENT_ID,
                 Document.COLUMN_MIME_TYPE,
-                Document.COLUMN_SIZE
+                Document.COLUMN_SIZE,
+                Document.COLUMN_FLAGS
         };
-        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(srcDirUri.getAuthority(),
-                DocumentsContract.getDocumentId(srcDirUri));
         Cursor cursor = null;
         try {
             // Iterate over srcs in the directory; copy to the destination directory.
-            cursor = mSrcClient.query(queryUri, queryColumns, null, null, null);
+            DocumentInfo srcInfo;
+            cursor = mSrcClient.query(srcDirInfo.derivedUri, queryColumns, null, null, null);
             while (cursor.moveToNext()) {
-                final String childMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
-                final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirUri,
-                        childMimeType, getCursorString(cursor, Document.COLUMN_DISPLAY_NAME));
-                final Uri childUri = DocumentsContract.buildDocumentUri(srcDirUri.getAuthority(),
-                        getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
-                if (Document.MIME_TYPE_DIR.equals(childMimeType)) {
-                    copyDirectoryHelper(childUri, dstUri, mode);
-                } else {
-                    copyFileHelper(childUri, dstUri, mode);
-                }
-            }
-            if (mode == TRANSFER_MODE_MOVE) {
-                try {
-                    DocumentsContract.deleteDocument(mSrcClient, srcDirUri);
-                } catch (RemoteException e) {
-                    // RemoteExceptions usually signal that the connection is dead, so there's no
-                    // point attempting to continue. Propagate the exception up so the copy job is
-                    // cancelled.
-                    Log.w(TAG, "Failed to clean up after move: " + srcDirUri, e);
-                    throw e;
-                }
+                srcInfo = DocumentInfo.fromCursor(cursor, srcDirInfo.authority);
+                copy(srcInfo, dstDirInfo, mode);
             }
         } finally {
             IoUtils.closeQuietly(cursor);
@@ -571,11 +578,11 @@
     /**
      * Handles copying a single file.
      *
-     * @param srcUri URI of the file to copy from.
-     * @param dstUri URI of the *file* to copy to. Must be created beforehand.
+     * @param srcUriInfo Info of the file to copy from.
+     * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand.
      * @throws RemoteException
      */
-    private void copyFileHelper(Uri srcUri, Uri dstUri, int mode)
+    private void copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, int mode)
             throws RemoteException {
         // Copy an individual file.
         CancellationSignal canceller = new CancellationSignal();
@@ -586,9 +593,26 @@
 
         IOException copyError = null;
         try {
-            srcFile = mSrcClient.openFile(srcUri, "r", canceller);
-            dstFile = mDstClient.openFile(dstUri, "w", canceller);
-            src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
+            // If the file is virtual, but can be converted to another format, then try to copy it
+            // as such format.
+            if (srcInfo.isVirtualDocument() && srcInfo.isTypedDocument()) {
+                final String[] streamTypes = mSrcClient.getStreamTypes(srcInfo.derivedUri, "*/*");
+                if (streamTypes.length > 0) {
+                    // Pick the first streamable format.
+                    final AssetFileDescriptor srcFileAsAsset =
+                            mSrcClient.openTypedAssetFileDescriptor(
+                                    srcInfo.derivedUri, streamTypes[0], null, canceller);
+                    srcFile = srcFileAsAsset.getParcelFileDescriptor();
+                    src = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
+                } else {
+                    // TODO: Log failures. b/26192412
+                    mFailedFiles.add(srcInfo);
+                }
+            } else {
+                srcFile = mSrcClient.openFile(srcInfo.derivedUri, "r", canceller);
+                src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
+            }
+            dstFile = mDstClient.openFile(dstInfo.derivedUri, "w", canceller);
             dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
 
             byte[] buffer = new byte[8192];
@@ -601,18 +625,7 @@
             srcFile.checkError();
         } catch (IOException e) {
             copyError = e;
-
-            try {
-                DocumentInfo info = DocumentInfo.fromUri(getContentResolver(), srcUri);
-                mFailedFiles.add(info);
-            } catch (FileNotFoundException ignore) {
-                // Generate a dummy DocumentInfo so an error still gets reflected in the UI for this
-                // file.
-                DocumentInfo info = new DocumentInfo();
-                info.derivedUri = srcUri;
-                info.displayName = "Unknown [" + srcUri + "]";
-                mFailedFiles.add(info);
-            }
+            mFailedFiles.add(srcInfo);
 
             if (dstFile != null) {
                 try {
@@ -627,26 +640,17 @@
             IoUtils.closeQuietly(dst);
         }
 
-
         if (copyError != null || mIsCancelled) {
             // Clean up half-copied files.
             canceller.cancel();
             try {
-                DocumentsContract.deleteDocument(mDstClient, dstUri);
+                DocumentsContract.deleteDocument(mDstClient, dstInfo.derivedUri);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed to clean up after copy error: " + dstUri, e);
+                Log.w(TAG, "Failed to clean up after copy error: " + dstInfo.derivedUri, e);
                 // RemoteExceptions usually signal that the connection is dead, so there's no point
                 // attempting to continue. Propagate the exception up so the copy job is cancelled.
                 throw e;
             }
-        } else if (mode == TRANSFER_MODE_MOVE) {
-            // Clean up src files after a successful move.
-            try {
-                DocumentsContract.deleteDocument(mSrcClient, srcUri);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to clean up after move: " + srcUri, e);
-                throw e;
-            }
         }
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index bf44013..0b6a09f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -101,21 +101,24 @@
             // from EXTRA_STACK intent extra. In this case, we'll skip other means of
             // loading or restoring the stack.
             if (!mState.stack.isEmpty()) {
+                if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
                 // When restoring from a stack, if a URI is present, it should only ever
                 // be a launch URI. Launch URIs support sensible activity management, but
-                // don't specify an real content target.
-                if (uri != null) {
-                    checkState(LauncherActivity.isLaunchUri(uri));
-                }
+                // don't specify a real content target.
+                checkState(uri == null || LauncherActivity.isLaunchUri(uri));
                 onCurrentDirectoryChanged(ANIM_NONE);
             } else if (DocumentsContract.isRootUri(this, uri)) {
+                if (DEBUG) Log.d(TAG, "Launching with root URI.");
                 // If we've got a specific root to display, restore that root using a dedicated
                 // authority. That way a misbehaving provider won't result in an ANR.
                 new RestoreRootTask(uri).executeOnExecutor(
                         ProviderExecutor.forAuthority(uri.getAuthority()));
             } else {
-                // Finally, we try to restore a stack from recents.
-                new RestoreStackTask().execute();
+                if (DEBUG) Log.d(TAG, "Launching into Home directory.");
+                // If all else fails, try to load "Home" directory.
+                uri = DocumentsContract.buildHomeUri();
+                new RestoreRootTask(uri).executeOnExecutor(
+                        ProviderExecutor.forAuthority(uri.getAuthority()));
             }
 
             // TODO: Ensure we're handling CopyService errors correctly across all activities.
@@ -159,7 +162,17 @@
     @Override
     protected void onPostCreate(Bundle savedInstanceState) {
         super.onPostCreate(savedInstanceState);
-        updateActionBar();
+        // This check avoids a flicker from "Recents" to "Home".
+        // Only update action bar at this point if there is an active
+        // serach. Why? Because this avoid an early (undesired) load of
+        // the recents root...which is the default root in other activities.
+        // In Files app "Home" is the default, but it is loaded async.
+        // updateActionBar will be called once Home root is loaded.
+        // Except while searching we need this call to ensure the
+        // search bits get layed out correctly.
+        if (mSearchManager.isSearching()) {
+            updateActionBar();
+        }
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 2d77c6a..770d011 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -316,12 +316,8 @@
         mAdapter = new DocumentsAdapter(context);
         mRecView.setAdapter(mAdapter);
 
-        mDefaultItemColor = context.getResources().getColor(android.R.color.transparent);
-        // Get the accent color.
-        TypedValue selColor = new TypedValue();
-        context.getTheme().resolveAttribute(android.R.attr.colorAccent, selColor, true);
-        // Set the opacity to 10%.
-        mSelectedItemColor = (selColor.data & 0x00ffffff) | 0x16000000;
+        mDefaultItemColor = context.getResources().getColor(R.color.item_doc_background);
+        mSelectedItemColor = context.getResources().getColor(R.color.item_doc_background_selected);
 
         GestureDetector.SimpleOnGestureListener listener =
                 new GestureDetector.SimpleOnGestureListener() {
@@ -943,6 +939,7 @@
 
         public void setSelected(boolean selected) {
             itemView.setActivated(selected);
+            itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
         }
 
         @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 69b574d..215c6e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -251,6 +251,14 @@
         return isDirectory() || isArchive();
     }
 
+    public boolean isVirtualDocument() {
+        return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
+    }
+
+    public boolean isTypedDocument() {
+        return (flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) != 0;
+    }
+
     public int hashCode() {
         return derivedUri.hashCode() + mimeType.hashCode();
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 71d8b34..f0dbfe9 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -137,11 +137,18 @@
         mBot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
     }
 
+    public void testLoadsHomeByDefault() throws Exception {
+        initTestFiles();
+
+        mDevice.waitForIdle();
+        mBot.assertWindowTitle("Home");
+    }
+
     public void testRootClickSetsWindowTitle() throws Exception {
         initTestFiles();
 
-        mBot.openRoot("Home");
-        mBot.assertWindowTitle("Home");
+        mBot.openRoot("Downloads");
+        mBot.assertWindowTitle("Downloads");
     }
 
     public void testFilesList_LiveUpdate() throws Exception {
diff --git a/packages/FusedLocation/res/values-de/strings.xml b/packages/FusedLocation/res/values-de/strings.xml
index d7e5faa..5c846d8 100644
--- a/packages/FusedLocation/res/values-de/strings.xml
+++ b/packages/FusedLocation/res/values-de/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbestimmung"</string>
+    <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbest."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index 3d9e901..da9863f 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -31,7 +31,7 @@
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"अयोग्य पिन कोड."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"चार्ज झाली"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"चार्ज होत आहे"</string>
-    <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"दृतपणे चार्ज होत आहे"</string>
+    <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"द्रुतपणे चार्ज होत आहे"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"धीमेपणे चार्ज होत आहे"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"आपले चार्जर कनेक्ट करा."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"अनलॉक करण्यासाठी मेनू दाबा."</string>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index 6fa0df2..1d72647 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -255,7 +255,7 @@
                 return;
             }
             if (mNumLoaded == 0) {
-                mDatabase.getMapper().startAddingChildDocuments(mIdentifier.mDocumentId);
+                mDatabase.getMapper().startAddingDocuments(mIdentifier.mDocumentId);
             }
             try {
                 mDatabase.getMapper().putChildDocuments(
@@ -266,7 +266,7 @@
                 mNumLoaded = 0;
             }
             if (getState() != STATE_LOADING) {
-                mDatabase.getMapper().stopAddingChildDocuments(mIdentifier.mDocumentId);
+                mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
             }
         }
 
@@ -275,7 +275,7 @@
             mError = message;
             mNumLoaded = 0;
             if (lastState == STATE_LOADING) {
-                mDatabase.getMapper().stopAddingChildDocuments(mIdentifier.mDocumentId);
+                mDatabase.getMapper().stopAddingDocuments(mIdentifier.mDocumentId);
             }
         }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index 0d9d60c..322246a 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -18,6 +18,7 @@
 
 import static com.android.mtp.MtpDatabaseConstants.*;
 
+import android.annotation.Nullable;
 import android.content.ContentValues;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -36,17 +37,18 @@
 
 import static com.android.mtp.MtpDatabase.strings;
 
-
 /**
  * Mapping operations for MtpDatabase.
  * Also see the comments of {@link MtpDatabase}.
  */
 class Mapper {
+    private static final String[] EMPTY_ARGS = new String[0];
     private final MtpDatabase mDatabase;
 
     /**
-     * Mapping mode for roots/documents where we start adding child documents.
+     * Mapping mode for a parent. The key is document ID of parent, or null for root documents.
      * Methods operate the state needs to be synchronized.
+     * TODO: Replace this with unboxing int map.
      */
     private final Map<String, Integer> mMappingMode = new HashMap<>();
 
@@ -54,48 +56,43 @@
         mDatabase = database;
     }
 
-    /**
-     * Invokes {@link #startAddingDocuments} for root documents.
-     * @param deviceId Device ID.
-     */
-    synchronized void startAddingRootDocuments(int deviceId) {
-        final String mappingStateKey = getRootDocumentsMappingStateKey(deviceId);
-        Preconditions.checkState(!mMappingMode.containsKey(mappingStateKey));
-        mMappingMode.put(
-                mappingStateKey,
-                startAddingDocuments(
-                        SELECTION_ROOT_DOCUMENTS, Integer.toString(deviceId)));
-    }
-
-    /**
-     * Invokes {@link #startAddingDocuments} for child of specific documents.
-     * @param parentDocumentId Document ID for parent document.
-     */
-    @VisibleForTesting
-    synchronized void startAddingChildDocuments(String parentDocumentId) {
-        final String mappingStateKey = getChildDocumentsMappingStateKey(parentDocumentId);
-        Preconditions.checkState(!mMappingMode.containsKey(mappingStateKey));
-        mMappingMode.put(
-                mappingStateKey,
-                startAddingDocuments(SELECTION_CHILD_DOCUMENTS, parentDocumentId));
+    synchronized String putDeviceDocument(int deviceId, String name, MtpRoot[] roots) {
+        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
+        Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null));
+        database.beginTransaction();
+        try {
+            final ContentValues[] valuesList = new ContentValues[1];
+            valuesList[0] = new ContentValues();
+            MtpDatabase.getDeviceDocumentValues(valuesList[0], deviceId, name, roots);
+            putDocuments(
+                    valuesList,
+                    COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
+                    EMPTY_ARGS,
+                    /* heuristic */ false,
+                    COLUMN_DEVICE_ID);
+            database.setTransactionSuccessful();
+            return valuesList[0].getAsString(Document.COLUMN_DOCUMENT_ID);
+        } finally {
+            database.endTransaction();
+        }
     }
 
     /**
      * Puts root information to database.
-     * @param deviceId Device ID
+     * @param parentDocumentId Document ID of device document.
      * @param resources Resources required to localize root name.
      * @param roots List of root information.
      * @return If roots are added or removed from the database.
      */
-    synchronized boolean putRootDocuments(int deviceId, Resources resources, MtpRoot[] roots) {
+    synchronized boolean putRootDocuments(
+            String parentDocumentId, Resources resources, MtpRoot[] roots) {
         final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
         database.beginTransaction();
         try {
             final boolean heuristic;
             final String mapColumn;
-            final String key = getRootDocumentsMappingStateKey(deviceId);
-            Preconditions.checkState(mMappingMode.containsKey(key));
-            switch (mMappingMode.get(key)) {
+            Preconditions.checkState(mMappingMode.containsKey(parentDocumentId));
+            switch (mMappingMode.get(parentDocumentId)) {
                 case MAP_BY_MTP_IDENTIFIER:
                     heuristic = false;
                     mapColumn = COLUMN_STORAGE_ID;
@@ -109,16 +106,14 @@
             }
             final ContentValues[] valuesList = new ContentValues[roots.length];
             for (int i = 0; i < roots.length; i++) {
-                if (roots[i].mDeviceId != deviceId) {
-                    throw new IllegalArgumentException();
-                }
                 valuesList[i] = new ContentValues();
-                MtpDatabase.getRootDocumentValues(valuesList[i], resources, roots[i]);
+                MtpDatabase.getStorageDocumentValues(
+                        valuesList[i], resources, parentDocumentId, roots[i]);
             }
             final boolean changed = putDocuments(
                     valuesList,
-                    SELECTION_ROOT_DOCUMENTS,
-                    Integer.toString(deviceId),
+                    COLUMN_PARENT_DOCUMENT_ID + "=?",
+                    strings(parentDocumentId),
                     heuristic,
                     mapColumn);
             final ContentValues values = new ContentValues();
@@ -156,9 +151,8 @@
     synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents) {
         final boolean heuristic;
         final String mapColumn;
-        final String key = getChildDocumentsMappingStateKey(parentId);
-        Preconditions.checkState(mMappingMode.containsKey(key));
-        switch (mMappingMode.get(key)) {
+        Preconditions.checkState(mMappingMode.containsKey(parentId));
+        switch (mMappingMode.get(parentId)) {
             case MAP_BY_MTP_IDENTIFIER:
                 heuristic = false;
                 mapColumn = COLUMN_OBJECT_HANDLE;
@@ -173,63 +167,15 @@
         final ContentValues[] valuesList = new ContentValues[documents.length];
         for (int i = 0; i < documents.length; i++) {
             valuesList[i] = new ContentValues();
-            MtpDatabase.getChildDocumentValues(
+            MtpDatabase.getObjectDocumentValues(
                     valuesList[i], deviceId, parentId, documents[i]);
         }
         putDocuments(
-                valuesList, SELECTION_CHILD_DOCUMENTS, parentId, heuristic, mapColumn);
-    }
-
-    /**
-     * Stops adding root documents.
-     * @param deviceId Device ID.
-     * @return True if new rows are added/removed.
-     */
-    synchronized boolean stopAddingRootDocuments(int deviceId) {
-        final String key = getRootDocumentsMappingStateKey(deviceId);
-        Preconditions.checkState(mMappingMode.containsKey(key));
-        switch (mMappingMode.get(key)) {
-            case MAP_BY_MTP_IDENTIFIER:
-                mMappingMode.remove(key);
-                return stopAddingDocuments(
-                        SELECTION_ROOT_DOCUMENTS,
-                        Integer.toString(deviceId),
-                        COLUMN_STORAGE_ID);
-            case MAP_BY_NAME:
-                mMappingMode.remove(key);
-                return stopAddingDocuments(
-                        SELECTION_ROOT_DOCUMENTS,
-                        Integer.toString(deviceId),
-                        Document.COLUMN_DISPLAY_NAME);
-            default:
-                throw new Error("Unexpected mapping state.");
-        }
-    }
-
-    /**
-     * Stops adding documents under the parent.
-     * @param parentId Document ID of the parent.
-     */
-    synchronized void stopAddingChildDocuments(String parentId) {
-        final String key = getChildDocumentsMappingStateKey(parentId);
-        Preconditions.checkState(mMappingMode.containsKey(key));
-        switch (mMappingMode.get(key)) {
-            case MAP_BY_MTP_IDENTIFIER:
-                stopAddingDocuments(
-                        SELECTION_CHILD_DOCUMENTS,
-                        parentId,
-                        COLUMN_OBJECT_HANDLE);
-                break;
-            case MAP_BY_NAME:
-                stopAddingDocuments(
-                        SELECTION_CHILD_DOCUMENTS,
-                        parentId,
-                        Document.COLUMN_DISPLAY_NAME);
-                break;
-            default:
-                throw new Error("Unexpected mapping state.");
-        }
-        mMappingMode.remove(key);
+                valuesList,
+                COLUMN_PARENT_DOCUMENT_ID + "=?",
+                strings(parentId),
+                heuristic,
+                mapColumn);
     }
 
     @VisibleForTesting
@@ -257,31 +203,42 @@
      * identifier or not. If all the documents have MTP identifier, it uses the identifier to find
      * a corresponding existing row. Otherwise it does heuristic.
      *
-     * @param selection Query matches valid documents.
-     * @param arg Argument for selection.
-     * @return Mapping mode.
+     * @param parentDocumentId Parent document ID or NULL for root documents.
      */
-    private int startAddingDocuments(String selection, String arg) {
+    void startAddingDocuments(@Nullable String parentDocumentId) {
+        Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId));
+        final String selection;
+        final String[] args;
+        if (parentDocumentId != null) {
+            selection = COLUMN_PARENT_DOCUMENT_ID + " = ?";
+            args = strings(parentDocumentId);
+        } else {
+            selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
+            args = EMPTY_ARGS;
+        }
+
         final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
         database.beginTransaction();
         try {
             // Delete all pending rows.
             mDatabase.deleteDocumentsAndRootsRecursively(
-                    selection + " AND " + COLUMN_ROW_STATE + "=?", strings(arg, ROW_STATE_PENDING));
+                    selection + " AND " + COLUMN_ROW_STATE + "=?",
+                    DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_PENDING)));
 
             // Set all documents as invalidated.
             final ContentValues values = new ContentValues();
             values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
-            database.update(TABLE_DOCUMENTS, values, selection, new String[] { arg });
+            database.update(TABLE_DOCUMENTS, values, selection, args);
 
             // If we have rows that does not have MTP identifier, do heuristic mapping by name.
             final boolean useNameForResolving = DatabaseUtils.queryNumEntries(
                     database,
                     TABLE_DOCUMENTS,
                     selection + " AND " + COLUMN_STORAGE_ID + " IS NULL",
-                    new String[] { arg }) > 0;
+                    args) > 0;
             database.setTransactionSuccessful();
-            return useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER;
+            mMappingMode.put(
+                    parentDocumentId, useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER);
         } finally {
             database.endTransaction();
         }
@@ -292,19 +249,19 @@
      * If the mapping mode is not heuristic, it just adds the rows to the database or updates the
      * existing rows with the new values. If the mapping mode is heuristic, it adds some new rows as
      * 'pending' state when that rows may be corresponding to existing 'invalidated' rows. Then
-     * {@link #stopAddingDocuments(String, String, String)} turns the pending rows into 'valid'
+     * {@link #stopAddingDocuments(String, String[], String)} turns the pending rows into 'valid'
      * rows. If the methods adds rows to database, it updates valueList with correct document ID.
      *
      * @param valuesList Values for documents to be stored in the database.
      * @param selection SQL where closure to select rows that shares the same parent.
-     * @param arg Argument for selection SQL.
+     * @param args Argument for selection SQL.
      * @param heuristic Whether the mapping mode is heuristic.
      * @return Whether the method adds new rows.
      */
     private boolean putDocuments(
             ContentValues[] valuesList,
             String selection,
-            String arg,
+            String[] args,
             boolean heuristic,
             String mappingKey) {
         final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
@@ -318,7 +275,9 @@
                         selection + " AND " +
                         COLUMN_ROW_STATE + "=? AND " +
                         mappingKey + "=?",
-                        strings(arg, ROW_STATE_INVALIDATED, values.getAsString(mappingKey)),
+                        DatabaseUtils.appendSelectionArgs(
+                                args,
+                                strings(ROW_STATE_INVALIDATED, values.getAsString(mappingKey))),
                         null,
                         null,
                         null,
@@ -362,12 +321,32 @@
      * Maps 'pending' document and 'invalidated' document that shares the same column of groupKey.
      * If the database does not find corresponding 'invalidated' document, it just removes
      * 'invalidated' document from the database.
-     * @param selection Query to select rows for resolving.
-     * @param arg Argument for selection SQL.
-     * @param groupKey Column name used to find corresponding rows.
+     * @param parentId Parent document ID or null for root documents.
      * @return Whether the methods adds or removed visible rows.
      */
-    private boolean stopAddingDocuments(String selection, String arg, String groupKey) {
+    boolean stopAddingDocuments(@Nullable String parentId) {
+        Preconditions.checkState(mMappingMode.containsKey(parentId));
+        final String selection;
+        final String[] args;
+        if (parentId != null) {
+            selection = COLUMN_PARENT_DOCUMENT_ID + "=?";
+            args = strings(parentId);
+        } else {
+            selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
+            args = EMPTY_ARGS;
+        }
+        final String groupKey;
+        switch (mMappingMode.get(parentId)) {
+            case MAP_BY_MTP_IDENTIFIER:
+                groupKey = parentId != null ? COLUMN_OBJECT_HANDLE : COLUMN_STORAGE_ID;
+                break;
+            case MAP_BY_NAME:
+                groupKey = Document.COLUMN_DISPLAY_NAME;
+                break;
+            default:
+                throw new Error("Unexpected mapping state.");
+        }
+        mMappingMode.remove(parentId);
         final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
         database.beginTransaction();
         try {
@@ -390,7 +369,7 @@
                             "group_concat(" + pendingIdQuery + ")"
                     },
                     selection,
-                    strings(arg),
+                    args,
                     groupKey,
                     "count(" + invalidatedIdQuery + ") = 1 AND count(" + pendingIdQuery + ") = 1",
                     null);
@@ -439,7 +418,7 @@
             // Delete all invalidated rows that cannot be mapped.
             if (mDatabase.deleteDocumentsAndRootsRecursively(
                     COLUMN_ROW_STATE + " = ? AND " + selection,
-                    strings(ROW_STATE_INVALIDATED, arg))) {
+                    DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
                 changed = true;
             }
 
@@ -452,7 +431,7 @@
                     TABLE_DOCUMENTS,
                     values,
                     COLUMN_ROW_STATE + " = ? AND " + selection,
-                    strings(ROW_STATE_PENDING, arg)) != 0) {
+                    DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_PENDING), args)) != 0) {
                 changed = true;
             }
             database.setTransactionSuccessful();
@@ -494,20 +473,4 @@
         return "CASE WHEN " + COLUMN_ROW_STATE + " = " + Integer.toString(state) +
                 " THEN " + a + " ELSE NULL END";
     }
-
-    /**
-     * @param deviceId Device ID.
-     * @return Key for {@link #mMappingMode}.
-     */
-    private static String getRootDocumentsMappingStateKey(int deviceId) {
-        return "RootDocuments/" + deviceId;
-    }
-
-    /**
-     * @param parentDocumentId Document ID for the parent document.
-     * @return Key for {@link #mMappingMode}.
-     */
-    private static String getChildDocumentsMappingStateKey(String parentDocumentId) {
-        return "ChildDocuments/" + parentDocumentId;
-    }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 51c0281..1ba3e31 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -22,7 +22,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
@@ -35,8 +35,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
-import java.io.File;
 import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -53,13 +54,13 @@
  * by comparing the directory structure and object name.
  *
  * To start putting documents into the database, the client needs to call
- * {@link Mapper#startAddingChildDocuments(String)} with the parent document ID. Also it
- * needs to call {@link Mapper#stopAddingChildDocuments(String)} after putting all child
+ * {@link Mapper#startAddingDocuments(String)} with the parent document ID. Also it
+ * needs to call {@link Mapper#stopAddingDocuments(String)} after putting all child
  * documents to the database. (All explanations are same for root documents)
  *
- * database.getMapper().startAddingChildDocuments();
+ * database.getMapper().startAddingDocuments();
  * database.getMapper().putChildDocuments();
- * database.getMapper().stopAddingChildDocuments();
+ * database.getMapper().stopAddingDocuments();
  *
  * To update the existing documents, the client code can repeat to call the three methods again.
  * The newly added rows update corresponding existing rows that have same MTP identifier like
@@ -107,11 +108,14 @@
      * @return Database cursor.
      */
     Cursor queryRoots(String[] columnNames) {
-        return mDatabase.query(
-                VIEW_ROOTS,
+        final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
+        builder.setTables(JOIN_ROOTS);
+        builder.setProjectionMap(COLUMN_MAP_ROOTS);
+        return builder.query(
+                mDatabase,
                 columnNames,
-                COLUMN_ROW_STATE + " IN (?, ?)",
-                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED),
+                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?",
+                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
                 null,
                 null,
                 null);
@@ -128,8 +132,8 @@
         return mDatabase.query(
                 TABLE_DOCUMENTS,
                 columnNames,
-                COLUMN_ROW_STATE + " IN (?, ?)",
-                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED),
+                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + "=?",
+                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
                 null,
                 null,
                 null);
@@ -216,7 +220,7 @@
      */
     String putNewDocument(int deviceId, String parentDocumentId, MtpObjectInfo info) {
         final ContentValues values = new ContentValues();
-        getChildDocumentValues(values, deviceId, parentDocumentId, info);
+        getObjectDocumentValues(values, deviceId, parentDocumentId, info);
         mDatabase.beginTransaction();
         try {
             final long id = mDatabase.insert(TABLE_DOCUMENTS, null, values);
@@ -307,32 +311,6 @@
         }
     }
 
-    /**
-     * Returns the set of device ID stored in the database.
-     */
-    int[] getDeviceIds() {
-        final Cursor cursor = mDatabase.query(
-                true,
-                TABLE_DOCUMENTS,
-                strings(COLUMN_DEVICE_ID),
-                null,
-                null,
-                null,
-                null,
-                null,
-                null);
-        try {
-            final int[] ids = new int[cursor.getCount()];
-            for (int i = 0; i < ids.length; i++) {
-                cursor.moveToNext();
-                ids[i] = cursor.getInt(0);
-            }
-            return ids;
-        } finally {
-            cursor.close();
-        }
-    }
-
     private boolean deleteDocumentsAndRoots(String selection, String[] args) {
         mDatabase.beginTransaction();
         try {
@@ -370,7 +348,6 @@
         public void onCreate(SQLiteDatabase db) {
             db.execSQL(QUERY_CREATE_DOCUMENTS);
             db.execSQL(QUERY_CREATE_ROOT_EXTRA);
-            db.execSQL(QUERY_CREATE_VIEW_ROOTS);
         }
 
         @Override
@@ -384,19 +361,43 @@
         context.deleteDatabase(DATABASE_NAME);
     }
 
+    static void getDeviceDocumentValues(
+            ContentValues values, int deviceId, String name, MtpRoot[] roots) {
+        values.clear();
+        values.put(COLUMN_DEVICE_ID, deviceId);
+        values.putNull(COLUMN_STORAGE_ID);
+        values.putNull(COLUMN_OBJECT_HANDLE);
+        values.putNull(COLUMN_PARENT_DOCUMENT_ID);
+        values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
+        values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE);
+        values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+        values.put(Document.COLUMN_DISPLAY_NAME, name);
+        values.putNull(Document.COLUMN_SUMMARY);
+        values.putNull(Document.COLUMN_LAST_MODIFIED);
+        values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
+        values.put(Document.COLUMN_FLAGS, 0);
+        long size = 0;
+        for (final MtpRoot root : roots) {
+            size += root.mMaxCapacity - root.mFreeSpace;
+        }
+        values.put(Document.COLUMN_SIZE, size);
+    }
+
     /**
      * Gets {@link ContentValues} for the given root.
      * @param values {@link ContentValues} that receives values.
      * @param resources Resources used to get localized root name.
      * @param root Root to be converted {@link ContentValues}.
      */
-    static void getRootDocumentValues(ContentValues values, Resources resources, MtpRoot root) {
+    static void getStorageDocumentValues(
+            ContentValues values, Resources resources, String parentDocumentId, MtpRoot root) {
         values.clear();
         values.put(COLUMN_DEVICE_ID, root.mDeviceId);
         values.put(COLUMN_STORAGE_ID, root.mStorageId);
         values.putNull(COLUMN_OBJECT_HANDLE);
-        values.putNull(COLUMN_PARENT_DOCUMENT_ID);
+        values.put(COLUMN_PARENT_DOCUMENT_ID, parentDocumentId);
         values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
+        values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_STORAGE);
         values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
         values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources));
         values.putNull(Document.COLUMN_SUMMARY);
@@ -414,7 +415,7 @@
      * @param parentId Parent document ID of the object.
      * @param info MTP object info.
      */
-    static void getChildDocumentValues(
+    static void getObjectDocumentValues(
             ContentValues values, int deviceId, String parentId, MtpObjectInfo info) {
         values.clear();
         final String mimeType = info.getFormat() == MtpConstants.FORMAT_ASSOCIATION ?
@@ -436,6 +437,7 @@
         values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
         values.put(COLUMN_PARENT_DOCUMENT_ID, parentId);
         values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
+        values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_OBJECT);
         values.put(Document.COLUMN_MIME_TYPE, mimeType);
         values.put(Document.COLUMN_DISPLAY_NAME, info.getName());
         values.putNull(Document.COLUMN_SUMMARY);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index 0ead2d5..a233589 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -16,9 +16,13 @@
 
 package com.android.mtp;
 
+import android.database.sqlite.SQLiteQueryBuilder;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Class containing MtpDatabase constants.
  */
@@ -41,14 +45,19 @@
     static final String TABLE_ROOT_EXTRA = "RootExtra";
 
     /**
-     * View to join Documents and RootExtra tables to provide roots information.
+     * 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA.
      */
-    static final String VIEW_ROOTS = "Roots";
+    static final String JOIN_ROOTS = createJoinFromClosure(
+            TABLE_DOCUMENTS,
+            TABLE_ROOT_EXTRA,
+            Document.COLUMN_DOCUMENT_ID,
+            Root.COLUMN_ROOT_ID);
 
     static final String COLUMN_DEVICE_ID = "device_id";
     static final String COLUMN_STORAGE_ID = "storage_id";
     static final String COLUMN_OBJECT_HANDLE = "object_handle";
     static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
+    static final String COLUMN_DOCUMENT_TYPE = "document_type";
     static final String COLUMN_ROW_STATE = "row_state";
 
     /**
@@ -83,11 +92,23 @@
      */
     static final int MAP_BY_NAME = 1;
 
+    /**
+     * Document that represents a MTP device.
+     */
+    static final int DOCUMENT_TYPE_DEVICE = 0;
+
+    /**
+     * Document that represents a MTP storage.
+     */
+    static final int DOCUMENT_TYPE_STORAGE = 1;
+
+    /**
+     * Document that represents a MTP object.
+     */
+    static final int DOCUMENT_TYPE_OBJECT = 2;
+
     static final String SELECTION_DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID + " = ?";
     static final String SELECTION_ROOT_ID = Root.COLUMN_ROOT_ID + " = ?";
-    static final String SELECTION_ROOT_DOCUMENTS =
-            COLUMN_DEVICE_ID + " = ? AND " + COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
-    static final String SELECTION_CHILD_DOCUMENTS = COLUMN_PARENT_DOCUMENT_ID + " = ?";
 
     static final String QUERY_CREATE_DOCUMENTS =
             "CREATE TABLE " + TABLE_DOCUMENTS + " (" +
@@ -98,6 +119,7 @@
             COLUMN_OBJECT_HANDLE + " INTEGER," +
             COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
             COLUMN_ROW_STATE + " INTEGER NOT NULL," +
+            COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," +
             Document.COLUMN_MIME_TYPE + " TEXT," +
             Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
             Document.COLUMN_SUMMARY + " TEXT," +
@@ -115,30 +137,31 @@
             Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);";
 
     /**
-     * Creates a view to join Documents table and RootExtra table on their primary keys to
-     * provide DocumentContract.Root equivalent information.
+     * Map for columns names to provide DocumentContract.Root compatible columns.
+     * @see SQLiteQueryBuilder#setProjectionMap(Map)
      */
-    static final String QUERY_CREATE_VIEW_ROOTS =
-            "CREATE VIEW " + VIEW_ROOTS + " AS SELECT " +
-                    TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " +
-                            Root.COLUMN_ROOT_ID + "," +
-                    TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS + "," +
-                    TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " +
-                            Root.COLUMN_ICON + "," +
-                    TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " +
-                            Root.COLUMN_TITLE + "," +
-                    TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " +
-                            Root.COLUMN_SUMMARY + "," +
-                    TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " +
-                    Root.COLUMN_DOCUMENT_ID + "," +
-                    TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES + "," +
-                    TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES + "," +
-                    TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES + "," +
-                    TABLE_DOCUMENTS + "." + COLUMN_ROW_STATE +
-            " FROM " + TABLE_DOCUMENTS + " INNER JOIN " + TABLE_ROOT_EXTRA +
-            " ON " +
-                    COLUMN_PARENT_DOCUMENT_ID + " IS NULL AND " +
-                    TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID +
-                    "=" +
-                    TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID;
+    static final Map<String, String> COLUMN_MAP_ROOTS;
+    static {
+        COLUMN_MAP_ROOTS = new HashMap<>();
+        COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID);
+        COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS);
+        COLUMN_MAP_ROOTS.put(Root.COLUMN_ICON, TABLE_DOCUMENTS + "." + Document.COLUMN_ICON);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_TITLE, TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME);
+        COLUMN_MAP_ROOTS.put(Root.COLUMN_SUMMARY, TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_DOCUMENT_ID, TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES);
+    }
+
+    private static String createJoinFromClosure(
+            String table1, String table2, String column1, String column2) {
+        return table1 + " INNER JOIN " + table2 +
+                " ON " + table1 + "." + column1 + " = " + table2 + "." + column2;
+    }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index d5f00e6..caa2024 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -190,9 +190,6 @@
             getDocumentLoader(parentIdentifier).clearTask(parentIdentifier);
             notifyChildDocumentsChange(parentIdentifier.mDocumentId);
         } catch (IOException error) {
-            for (final StackTraceElement element : error.getStackTrace()) {
-                Log.e("hirono", element.toString());
-            }
             throw new FileNotFoundException(error.getMessage());
         }
     }
@@ -293,19 +290,11 @@
     }
 
     /**
-     * Reopens MTP devices based on database state.
+     * Clears MTP identifier in the database.
      */
     private void resume() {
         synchronized (mDeviceListLock) {
             mDatabase.getMapper().clearMapping();
-            final int[] ids = mDatabase.getDeviceIds();
-            for (final int id : ids) {
-                try {
-                    openDevice(id);
-                } catch (IOException exception) {
-                    mDatabase.removeDeviceRows(id);
-                }
-            }
         }
     }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index df2ab01..197dec8 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -7,8 +7,11 @@
 import android.os.Process;
 import android.provider.DocumentsContract;
 import android.util.Log;
+import android.util.SparseArray;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
@@ -106,30 +109,42 @@
             int pollingCount = 0;
             while (!Thread.interrupted()) {
                 final int[] deviceIds = mManager.getOpenedDeviceIds();
-                if (deviceIds.length == 0) {
-                    return;
-                }
+                final Map<String, MtpRoot[]> rootsMap = new HashMap<>();
                 boolean changed = false;
-                for (int deviceId : deviceIds) {
+
+                // Update devices.
+                mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
+                for (final int deviceId : deviceIds) {
                     try {
                         final MtpRoot[] roots = mManager.getRoots(deviceId);
-                        mDatabase.getMapper().startAddingRootDocuments(deviceId);
-                        try {
-                            if (mDatabase.getMapper().putRootDocuments(
-                                    deviceId, mResources, roots)) {
-                                changed = true;
-                            }
-                        } finally {
-                            if (mDatabase.getMapper().stopAddingRootDocuments(deviceId)) {
-                                changed = true;
-                            }
+                        final String id = mDatabase.getMapper().putDeviceDocument(
+                                deviceId,
+                                mManager.getDeviceName(deviceId),
+                                roots);
+                        if (id != null) {
+                            changed = true;
+                            rootsMap.put(id, roots);
                         }
-                    } catch (IOException | SQLiteException exception) {
+                    } catch (IOException exception) {
                         // The error may happen on the device. We would like to continue getting
                         // roots for other devices.
                         Log.e(MtpDocumentsProvider.TAG, exception.getMessage());
                     }
                 }
+                mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */);
+
+                // Update roots.
+                for (final String documentId : rootsMap.keySet()) {
+                    mDatabase.getMapper().startAddingDocuments(documentId);
+                    if (mDatabase.getMapper().putRootDocuments(
+                            documentId, mResources, rootsMap.get(documentId))) {
+                        changed = true;
+                    }
+                    if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
+                        changed = true;
+                    }
+                }
+
                 if (changed) {
                     notifyChange();
                 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index f0b4343..7bd9a17 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -40,11 +40,11 @@
     @Override
     public void setUp() {
         mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, new TestResources(), new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", new TestResources(), new MtpRoot[] {
                 new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "")
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
         mManager = new BlockableTestMtpManager(getContext());
         mResolver = new TestContentResolver();
         mLoader = new DocumentLoader(mManager, mResolver, mDatabase);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 67b0672..6d57c5b 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -27,7 +27,9 @@
 
 import java.io.FileNotFoundException;
 
+import static android.provider.DocumentsContract.Document.*;
 import static com.android.mtp.MtpDatabase.strings;
+import static com.android.mtp.MtpDatabaseConstants.*;
 
 @SmallTest
 public class MtpDatabaseTest extends AndroidTestCase {
@@ -42,7 +44,8 @@
         DocumentsContract.Document.COLUMN_LAST_MODIFIED,
         DocumentsContract.Document.COLUMN_ICON,
         DocumentsContract.Document.COLUMN_FLAGS,
-        DocumentsContract.Document.COLUMN_SIZE
+        DocumentsContract.Document.COLUMN_SIZE,
+        MtpDatabaseConstants.COLUMN_DOCUMENT_TYPE
     };
 
     private final TestResources resources = new TestResources();
@@ -59,9 +62,21 @@
         mDatabase = null;
     }
 
+    private static int getInt(Cursor cursor, String columnName) {
+        return cursor.getInt(cursor.getColumnIndex(columnName));
+    }
+
+    private static boolean isNull(Cursor cursor, String columnName) {
+        return cursor.isNull(cursor.getColumnIndex(columnName));
+    }
+
+    private static String getString(Cursor cursor, String columnName) {
+        return cursor.getString(cursor.getColumnIndex(columnName));
+    }
+
     public void testPutRootDocuments() throws Exception {
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, ""),
                 new MtpRoot(0, 2, "Device", "Storage", 2000, 4000, ""),
                 new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 3000, 6000,"")
@@ -72,25 +87,27 @@
             assertEquals(3, cursor.getCount());
 
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("deviceId", 0, cursor.getInt(1));
-            assertEquals("storageId", 1, cursor.getInt(2));
-            assertTrue("objectHandle", cursor.isNull(3));
-            assertEquals("mimeType", DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(4));
-            assertEquals("displayName", "Device Storage", cursor.getString(5));
-            assertTrue("summary", cursor.isNull(6));
-            assertTrue("lastModified", cursor.isNull(7));
-            assertEquals("icon", R.drawable.ic_root_mtp, cursor.getInt(8));
-            assertEquals("flag", 0, cursor.getInt(9));
-            assertEquals("size", 1000, cursor.getInt(10));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
+            assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
+            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+            assertTrue(isNull(cursor, COLUMN_SUMMARY));
+            assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
+            assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
+            assertEquals(0, getInt(cursor, COLUMN_FLAGS));
+            assertEquals(1000, getInt(cursor, COLUMN_SIZE));
+            assertEquals(
+                    MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
 
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertEquals("displayName", "Device Storage", cursor.getString(5));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.moveToNext();
-            assertEquals("documentId", 3, cursor.getInt(0));
-            assertEquals("displayName", "Device /@#%&<>Storage", cursor.getString(5));
+            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals("Device /@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.close();
         }
@@ -152,7 +169,7 @@
     }
 
     public void testPutChildDocuments() throws Exception {
-        mDatabase.getMapper().startAddingChildDocuments("parentId");
+        mDatabase.getMapper().startAddingDocuments("parentId");
         mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
                 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
@@ -163,55 +180,61 @@
         assertEquals(3, cursor.getCount());
 
         cursor.moveToNext();
-        assertEquals("documentId", 1, cursor.getInt(0));
-        assertEquals("deviceId", 0, cursor.getInt(1));
-        assertEquals("storageId", 0, cursor.getInt(2));
-        assertEquals("objectHandle", 100, cursor.getInt(3));
-        assertEquals("mimeType", "text/plain", cursor.getString(4));
-        assertEquals("displayName", "note.txt", cursor.getString(5));
-        assertTrue("summary", cursor.isNull(6));
-        assertTrue("lastModified", cursor.isNull(7));
-        assertTrue("icon", cursor.isNull(8));
+        assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+        assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
+        assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
+        assertEquals(100, getInt(cursor, COLUMN_OBJECT_HANDLE));
+        assertEquals("text/plain", getString(cursor, COLUMN_MIME_TYPE));
+        assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
+        assertTrue(isNull(cursor, COLUMN_SUMMARY));
+        assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
+        assertTrue(isNull(cursor, COLUMN_ICON));
         assertEquals(
-                "flag",
+                COLUMN_FLAGS,
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
                 DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
                 cursor.getInt(9));
-        assertEquals("size", 1024, cursor.getInt(10));
+        assertEquals(1024, getInt(cursor, COLUMN_SIZE));
+        assertEquals(
+                MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
 
         cursor.moveToNext();
-        assertEquals("documentId", 2, cursor.getInt(0));
-        assertEquals("deviceId", 0, cursor.getInt(1));
-        assertEquals("storageId", 0, cursor.getInt(2));
-        assertEquals("objectHandle", 101, cursor.getInt(3));
-        assertEquals("mimeType", "image/jpeg", cursor.getString(4));
-        assertEquals("displayName", "image.jpg", cursor.getString(5));
-        assertTrue("summary", cursor.isNull(6));
-        assertTrue("lastModified", cursor.isNull(7));
-        assertTrue("icon", cursor.isNull(8));
+        assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+        assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
+        assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
+        assertEquals(101, getInt(cursor, COLUMN_OBJECT_HANDLE));
+        assertEquals("image/jpeg", getString(cursor, COLUMN_MIME_TYPE));
+        assertEquals("image.jpg", getString(cursor, COLUMN_DISPLAY_NAME));
+        assertTrue(isNull(cursor, COLUMN_SUMMARY));
+        assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
+        assertTrue(isNull(cursor, COLUMN_ICON));
         assertEquals(
-                "flag",
+                COLUMN_FLAGS,
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
                 DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
                 cursor.getInt(9));
-        assertEquals("size", 2 * 1024 * 1024, cursor.getInt(10));
+        assertEquals(2 * 1024 * 1024, getInt(cursor, COLUMN_SIZE));
+        assertEquals(
+                MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
 
         cursor.moveToNext();
-        assertEquals("documentId", 3, cursor.getInt(0));
-        assertEquals("deviceId", 0, cursor.getInt(1));
-        assertEquals("storageId", 0, cursor.getInt(2));
-        assertEquals("objectHandle", 102, cursor.getInt(3));
-        assertEquals("mimeType", "audio/mpeg", cursor.getString(4));
-        assertEquals("displayName", "music.mp3", cursor.getString(5));
-        assertTrue("summary", cursor.isNull(6));
-        assertTrue("lastModified", cursor.isNull(7));
-        assertTrue("icon", cursor.isNull(8));
+        assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+        assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
+        assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID));
+        assertEquals(102, getInt(cursor, COLUMN_OBJECT_HANDLE));
+        assertEquals("audio/mpeg", getString(cursor, COLUMN_MIME_TYPE));
+        assertEquals("music.mp3", getString(cursor, COLUMN_DISPLAY_NAME));
+        assertTrue(isNull(cursor, COLUMN_SUMMARY));
+        assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
+        assertTrue(isNull(cursor, COLUMN_ICON));
         assertEquals(
-                "flag",
+                COLUMN_FLAGS,
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
                 DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
                 cursor.getInt(9));
-        assertEquals("size", 3 * 1024 * 1024, cursor.getInt(10));
+        assertEquals(3 * 1024 * 1024, getInt(cursor, COLUMN_SIZE));
+        assertEquals(
+                MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE));
 
         cursor.close();
     }
@@ -227,8 +250,8 @@
                 Root.COLUMN_AVAILABLE_BYTES
         };
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 1000, 0, ""),
                 new MtpRoot(0, 101, "Device", "Storage B", 1001, 0, "")
         });
@@ -237,13 +260,13 @@
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("storageId", 100, cursor.getInt(1));
-            assertEquals("name", "Device Storage A", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertEquals("storageId", 101, cursor.getInt(1));
-            assertEquals("name", "Device Storage B", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(101, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -251,11 +274,11 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 1000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 2, cursor.getInt(0));
-            assertEquals("availableBytes", 1001, cursor.getInt(1));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
 
@@ -265,13 +288,13 @@
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertTrue("storageId", cursor.isNull(1));
-            assertEquals("name", "Device Storage A", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertTrue("storageId", cursor.isNull(1));
-            assertEquals("name", "Device Storage B", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -279,16 +302,16 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 1000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 2, cursor.getInt(0));
-            assertEquals("availableBytes", 1001, cursor.getInt(1));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage A", 2000, 0, ""),
                 new MtpRoot(0, 202, "Device", "Storage C", 2002, 0, "")
         });
@@ -297,17 +320,17 @@
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(3, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertTrue("storageId", cursor.isNull(1));
-            assertEquals("name", "Device Storage A", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertTrue("storageId", cursor.isNull(1));
-            assertEquals("name", "Device Storage B", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 4, cursor.getInt(0));
-            assertEquals("storageId", 202, cursor.getInt(1));
-            assertEquals("name", "Device Storage C", cursor.getString(2));
+            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -315,30 +338,30 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(3, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 1000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 2, cursor.getInt(0));
-            assertEquals("availableBytes", 1001, cursor.getInt(1));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 4, cursor.getInt(0));
-            assertEquals("availableBytes", 2002, cursor.getInt(1));
+            assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2002, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
 
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("storageId", 200, cursor.getInt(1));
-            assertEquals("name", "Device Storage A", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 4, cursor.getInt(0));
-            assertEquals("storageId", 202, cursor.getInt(1));
-            assertEquals("name", "Device Storage C", cursor.getString(2));
+            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -346,11 +369,11 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 2000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 4, cursor.getInt(0));
-            assertEquals("availableBytes", 2002, cursor.getInt(1));
+            assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2002, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
     }
@@ -361,7 +384,7 @@
                 MtpDatabaseConstants.COLUMN_OBJECT_HANDLE,
                 DocumentsContract.Document.COLUMN_DISPLAY_NAME
         };
-        mDatabase.getMapper().startAddingChildDocuments("parentId");
+        mDatabase.getMapper().startAddingDocuments("parentId");
         mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
                 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024),
@@ -374,24 +397,24 @@
             assertEquals(3, cursor.getCount());
 
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertTrue("objectHandle", cursor.isNull(1));
-            assertEquals("name", "note.txt", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertTrue("objectHandle", cursor.isNull(1));
-            assertEquals("name", "image.jpg", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals("image.jpg", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.moveToNext();
-            assertEquals("documentId", 3, cursor.getInt(0));
-            assertTrue("objectHandle", cursor.isNull(1));
-            assertEquals("name", "music.mp3", cursor.getString(2));
+            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals("music.mp3", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.close();
         }
 
-        mDatabase.getMapper().startAddingChildDocuments("parentId");
+        mDatabase.getMapper().startAddingDocuments("parentId");
         mDatabase.getMapper().putChildDocuments(0, "parentId", new MtpObjectInfo[] {
                 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 createDocument(203, "video.mp4", MtpConstants.FORMAT_MP4_CONTAINER, 1024),
@@ -402,28 +425,28 @@
             assertEquals(4, cursor.getCount());
 
             cursor.moveToPosition(3);
-            assertEquals("documentId", 5, cursor.getInt(0));
-            assertEquals("objectHandle", 203, cursor.getInt(1));
-            assertEquals("name", "video.mp4", cursor.getString(2));
+            assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.close();
         }
 
-        mDatabase.getMapper().stopAddingChildDocuments("parentId");
+        mDatabase.getMapper().stopAddingDocuments("parentId");
 
         {
             final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId");
             assertEquals(2, cursor.getCount());
 
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("objectHandle", 200, cursor.getInt(1));
-            assertEquals("name", "note.txt", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME));
 
             cursor.moveToNext();
-            assertEquals("documentId", 5, cursor.getInt(0));
-            assertEquals("objectHandle", 203, cursor.getInt(1));
-            assertEquals("name", "video.mp4", cursor.getString(2));
+            assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
     }
@@ -438,12 +461,12 @@
                 Root.COLUMN_ROOT_ID,
                 Root.COLUMN_AVAILABLE_BYTES
         };
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().startAddingRootDocuments(1);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocIdA");
+        mDatabase.getMapper().startAddingDocuments("deviceDocIdB");
+        mDatabase.getMapper().putRootDocuments("deviceDocIdA", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage", 0, 0, "")
         });
-        mDatabase.getMapper().putRootDocuments(1, resources, new MtpRoot[] {
+        mDatabase.getMapper().putRootDocuments("deviceDocIdB", resources, new MtpRoot[] {
                 new MtpRoot(1, 100, "Device", "Storage", 0, 0, "")
         });
 
@@ -451,13 +474,13 @@
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("storageId", 100, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertEquals("storageId", 100, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -465,38 +488,38 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 0, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 2, cursor.getInt(0));
-            assertEquals("availableBytes", 0, cursor.getInt(1));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
 
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().startAddingRootDocuments(1);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocIdA");
+        mDatabase.getMapper().startAddingDocuments("deviceDocIdB");
+        mDatabase.getMapper().putRootDocuments("deviceDocIdA", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage", 2000, 0, "")
         });
-        mDatabase.getMapper().putRootDocuments(1, resources, new MtpRoot[] {
+        mDatabase.getMapper().putRootDocuments("deviceDocIdB", resources, new MtpRoot[] {
                 new MtpRoot(1, 300, "Device", "Storage", 3000, 0, "")
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
-        mDatabase.getMapper().stopAddingRootDocuments(1);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocIdA");
+        mDatabase.getMapper().stopAddingDocuments("deviceDocIdB");
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("storageId", 200, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertEquals("storageId", 300, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -504,11 +527,11 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 2000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 2, cursor.getInt(0));
-            assertEquals("availableBytes", 3000, cursor.getInt(1));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
     }
@@ -519,8 +542,8 @@
                 MtpDatabaseConstants.COLUMN_OBJECT_HANDLE
         };
 
-        mDatabase.getMapper().startAddingChildDocuments("parentId1");
-        mDatabase.getMapper().startAddingChildDocuments("parentId2");
+        mDatabase.getMapper().startAddingDocuments("parentId1");
+        mDatabase.getMapper().startAddingDocuments("parentId2");
         mDatabase.getMapper().putChildDocuments(0, "parentId1", new MtpObjectInfo[] {
                 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
         });
@@ -529,30 +552,30 @@
         });
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingChildDocuments("parentId1");
-        mDatabase.getMapper().startAddingChildDocuments("parentId2");
+        mDatabase.getMapper().startAddingDocuments("parentId1");
+        mDatabase.getMapper().startAddingDocuments("parentId2");
         mDatabase.getMapper().putChildDocuments(0, "parentId1", new MtpObjectInfo[] {
                 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
         });
         mDatabase.getMapper().putChildDocuments(0, "parentId2", new MtpObjectInfo[] {
                 createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
         });
-        mDatabase.getMapper().stopAddingChildDocuments("parentId1");
+        mDatabase.getMapper().stopAddingDocuments("parentId1");
 
         {
             final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId1");
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("objectHandle", 200, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE));
             cursor.close();
         }
         {
             final Cursor cursor = mDatabase.queryChildDocuments(columns, "parentId2");
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertTrue("objectHandle", cursor.isNull(1));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
             cursor.close();
         }
     }
@@ -568,39 +591,39 @@
                 Root.COLUMN_AVAILABLE_BYTES
         };
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 300, "Device", "Storage", 3000, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("storageId", 300, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
         {
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 3000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
     }
@@ -616,41 +639,41 @@
                 Root.COLUMN_AVAILABLE_BYTES
         };
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""),
                 new MtpRoot(0, 201, "Device", "Storage", 2001, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 2, cursor.getInt(0));
-            assertEquals("storageId", 200, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals("documentId", 3, cursor.getInt(0));
-            assertEquals("storageId", 201, cursor.getInt(1));
-            assertEquals("name", "Device Storage", cursor.getString(2));
+            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(201, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
         {
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 2, cursor.getInt(0));
-            assertEquals("availableBytes", 2000, cursor.getInt(1));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals("rootId", 3, cursor.getInt(0));
-            assertEquals("availableBytes", 2001, cursor.getInt(1));
+            assertEquals(3, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
     }
@@ -658,17 +681,17 @@
     public void testReplaceExistingRoots() {
         // The client code should be able to replace existing rows with new information.
         // Add one.
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
         // Replace it.
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage B", 1000, 1000, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
         {
             final String[] columns = new String[] {
                     DocumentsContract.Document.COLUMN_DOCUMENT_ID,
@@ -678,9 +701,9 @@
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("documentId", 1, cursor.getInt(0));
-            assertEquals("storageId", 100, cursor.getInt(1));
-            assertEquals("name", "Device Storage B", cursor.getString(2));
+            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
+            assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
         {
@@ -691,8 +714,8 @@
             final Cursor cursor = mDatabase.queryRoots(columns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("rootId", 1, cursor.getInt(0));
-            assertEquals("availableBytes", 1000, cursor.getInt(1));
+            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
     }
@@ -700,8 +723,8 @@
     public void testFailToReplaceExisitingUnmappedRoots() {
         // The client code should not be able to replace rows before resolving 'unmapped' rows.
         // Add one.
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
@@ -709,15 +732,15 @@
         assertEquals(1, oldCursor.getCount());
 
         // Add one.
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 101, "Device", "Storage B", 1000, 1000, ""),
         });
         // Add one more before resolving unmapped documents.
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 102, "Device", "Storage B", 1000, 1000, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         // Because the roots shares the same name, the roots should have new IDs.
         final Cursor newCursor = mDatabase.queryRoots(strings(Root.COLUMN_ROOT_ID));
@@ -733,11 +756,11 @@
     }
 
     public void testQueryDocument() {
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         final Cursor cursor = mDatabase.queryDocument("1", strings(Document.COLUMN_DISPLAY_NAME));
         assertEquals(1, cursor.getCount());
@@ -747,48 +770,48 @@
     }
 
     public void testGetParentId() throws FileNotFoundException {
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
-        mDatabase.getMapper().startAddingChildDocuments("1");
+        mDatabase.getMapper().startAddingDocuments("1");
         mDatabase.getMapper().putChildDocuments(
                 0,
                 "1",
                 new MtpObjectInfo[] {
                         createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 });
-        mDatabase.getMapper().stopAddingChildDocuments("1");
+        mDatabase.getMapper().stopAddingDocuments("1");
 
         assertEquals("1", mDatabase.getParentId("2"));
     }
 
     public void testDeleteDocument() {
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
-        mDatabase.getMapper().startAddingChildDocuments("1");
+        mDatabase.getMapper().startAddingDocuments("1");
         mDatabase.getMapper().putChildDocuments(
                 0,
                 "1",
                 new MtpObjectInfo[] {
                         createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024),
                 });
-        mDatabase.getMapper().stopAddingChildDocuments("1");
+        mDatabase.getMapper().stopAddingDocuments("1");
 
-        mDatabase.getMapper().startAddingChildDocuments("2");
+        mDatabase.getMapper().startAddingDocuments("2");
         mDatabase.getMapper().putChildDocuments(
                 0,
                 "2",
                 new MtpObjectInfo[] {
                         createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024),
                 });
-        mDatabase.getMapper().stopAddingChildDocuments("2");
+        mDatabase.getMapper().stopAddingDocuments("2");
 
         mDatabase.deleteDocument("2");
 
@@ -810,11 +833,11 @@
     }
 
     public void testPutNewDocument() {
-        mDatabase.getMapper().startAddingRootDocuments(0);
-        mDatabase.getMapper().putRootDocuments(0, resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("deviceDocId");
+        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
-        mDatabase.getMapper().stopAddingRootDocuments(0);
+        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         assertEquals(
                 "2",
@@ -832,12 +855,12 @@
 
         // The new document should not be mapped with existing invalidated document.
         mDatabase.getMapper().clearMapping();
-        mDatabase.getMapper().startAddingChildDocuments("1");
+        mDatabase.getMapper().startAddingDocuments("1");
         mDatabase.putNewDocument(
                 0,
                 "1",
                 createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024));
-        mDatabase.getMapper().stopAddingChildDocuments("1");
+        mDatabase.getMapper().stopAddingDocuments("1");
 
         {
             final Cursor cursor =
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index dc6f79e..b0e9722 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -138,11 +138,11 @@
             final Cursor cursor = mProvider.queryRoots(null);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("1", cursor.getString(0));
+            assertEquals("2", cursor.getString(0));
             assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device A Storage A", cursor.getString(3));
-            assertEquals("1", cursor.getString(4));
+            assertEquals("2", cursor.getString(4));
             assertEquals(1024, cursor.getInt(5));
         }
 
@@ -153,11 +153,11 @@
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
             cursor.moveToNext();
-            assertEquals("2", cursor.getString(0));
+            assertEquals("4", cursor.getString(0));
             assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
-            assertEquals("2", cursor.getString(4));
+            assertEquals("4", cursor.getString(4));
             assertEquals(2048, cursor.getInt(5));
         }
     }
@@ -185,11 +185,11 @@
             final Cursor cursor = mProvider.queryRoots(null);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals("1", cursor.getString(0));
+            assertEquals("2", cursor.getString(0));
             assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
-            assertEquals("1", cursor.getString(4));
+            assertEquals("2", cursor.getString(4));
             assertEquals(2048, cursor.getInt(5));
         }
     }
@@ -216,12 +216,12 @@
                                 .build()
                 });
 
-        final Cursor cursor = mProvider.queryDocument("2", null);
+        final Cursor cursor = mProvider.queryDocument("3", null);
         assertEquals(1, cursor.getCount());
 
         cursor.moveToNext();
 
-        assertEquals("2", cursor.getString(0));
+        assertEquals("3", cursor.getString(0));
         assertEquals("image/jpeg", cursor.getString(1));
         assertEquals("image.jpg", cursor.getString(2));
         assertEquals(1422716400000L, cursor.getLong(3));
@@ -255,11 +255,11 @@
                                 .build()
                 });
 
-        final Cursor cursor = mProvider.queryDocument("2", null);
+        final Cursor cursor = mProvider.queryDocument("3", null);
         assertEquals(1, cursor.getCount());
 
         cursor.moveToNext();
-        assertEquals("2", cursor.getString(0));
+        assertEquals("3", cursor.getString(0));
         assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
         assertEquals("directory", cursor.getString(2));
         assertEquals(1422716400000L, cursor.getLong(3));
@@ -287,11 +287,11 @@
                         4096 /* total space */,
                         "" /* no volume identifier */)
         });
-        final Cursor cursor = mProvider.queryDocument("1", null);
+        final Cursor cursor = mProvider.queryDocument("2", null);
         assertEquals(1, cursor.getCount());
 
         cursor.moveToNext();
-        assertEquals("1", cursor.getString(0));
+        assertEquals("2", cursor.getString(0));
         assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
         assertEquals("Device A Storage A", cursor.getString(2));
         assertTrue(cursor.isNull(3));
@@ -325,7 +325,7 @@
         assertEquals(1, cursor.getCount());
 
         assertTrue(cursor.moveToNext());
-        assertEquals("2", cursor.getString(0));
+        assertEquals("3", cursor.getString(0));
         assertEquals("image/jpeg", cursor.getString(1));
         assertEquals("image.jpg", cursor.getString(2));
         assertEquals(0, cursor.getLong(3));
@@ -376,7 +376,7 @@
                     .build()
         });
 
-        mProvider.deleteDocument("2");
+        mProvider.deleteDocument("3");
         assertEquals(1, mResolver.getChangeCount(
                 DocumentsContract.buildChildDocumentsUri(
                         MtpDocumentsProvider.AUTHORITY, "1")));
@@ -398,7 +398,7 @@
                     .build()
         });
         try {
-            mProvider.deleteDocument("3");
+            mProvider.deleteDocument("4");
             fail();
         } catch (Throwable e) {
             assertTrue(e instanceof IOException);
@@ -408,34 +408,6 @@
                         MtpDocumentsProvider.AUTHORITY, "1")));
     }
 
-    @MediumTest
-    public void testPauseAndResume() throws Exception {
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_FILE);
-        mMtpManager.addValidDevice(0);
-        mProvider.openDevice(0);
-        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 0, 0, "")});
-
-        {
-            final Cursor cursor = mProvider.queryRoots(
-                    strings(DocumentsContract.Root.COLUMN_ROOT_ID));
-            cursor.moveToNext();
-            assertEquals(1, cursor.getInt(0));
-        }
-
-        mProvider.shutdown();
-        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_FILE);
-
-        {
-            // We can still fetch roots after relaunching the provider.
-            final Cursor cursor = mProvider.queryRoots(
-                    strings(DocumentsContract.Root.COLUMN_ROOT_ID));
-            assertEquals(1, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, cursor.getInt(0));
-            assertEquals(1, mMtpManager.getOpenedDeviceIds().length);
-        }
-    }
-
     private void setupProvider(int flag) {
         mDatabase = new MtpDatabase(getContext(), flag);
         mProvider = new MtpDocumentsProvider();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 3833799..ddc18a4 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -196,4 +196,9 @@
         }
         return result;
     }
+
+    @Override
+    String getDeviceName(int deviceId) throws IOException {
+        return "Device";
+    }
 }
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index d7ef503..df58657 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -138,7 +138,7 @@
     <string name="development_settings_title" msgid="215179176067683667">"Opcións de programador"</string>
     <string name="development_settings_enable" msgid="542530994778109538">"Activar opcións de programador"</string>
     <string name="development_settings_summary" msgid="1815795401632854041">"Definir as opcións de desenvolvemento de aplicacións"</string>
-    <string name="development_settings_not_available" msgid="4308569041701535607">"As opcións do programador non están dispoñibles para este usuario"</string>
+    <string name="development_settings_not_available" msgid="4308569041701535607">"As opcións de programador non están dispoñibles para este usuario"</string>
     <string name="vpn_settings_not_available" msgid="956841430176985598">"A configuración da VPN non está dispoñible para este usuario"</string>
     <string name="tethering_settings_not_available" msgid="6765770438438291012">"A configuración da ancoraxe non está dispoñible para este usuario"</string>
     <string name="apn_settings_not_available" msgid="7873729032165324000">"A configuración do nome do punto de acceso non está dispoñible para este usuario"</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 43d9790..77c5ab8 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -136,7 +136,7 @@
     <string name="category_personal" msgid="1299663247844969448">"Жеке"</string>
     <string name="category_work" msgid="8699184680584175622">"Жумуш"</string>
     <string name="development_settings_title" msgid="215179176067683667">"Иштеп чыгуучунун параметрлери"</string>
-    <string name="development_settings_enable" msgid="542530994778109538">"Иштеп чыгуучунун параметрлери иштетүү"</string>
+    <string name="development_settings_enable" msgid="542530994778109538">"Иштеп чыгуучунун параметрлерин иштетүү"</string>
     <string name="development_settings_summary" msgid="1815795401632854041">"Колдонмо өндүрүү мүмкүнчүлүктөрүн орнотуу"</string>
     <string name="development_settings_not_available" msgid="4308569041701535607">"Бул колдонуучуга өнүктүүрүүчү мүмкүнчүлүктөрү берилген эмес."</string>
     <string name="vpn_settings_not_available" msgid="956841430176985598">"Бул колдонуучу VPN жөндөөлөрүн колдоно албайт"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 82e8dc6..1033bb19 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -141,7 +141,7 @@
     <string name="development_settings_not_available" msgid="4308569041701535607">"Bu foydalanuvchiga dasturchi imkoniyatlari taqdim etilmagan"</string>
     <string name="vpn_settings_not_available" msgid="956841430176985598">"Ushbu foydalanuvchi uchun VPN sozlamalari mavjud emas"</string>
     <string name="tethering_settings_not_available" msgid="6765770438438291012">"Ushbu foydalanuvchi uchun Modem rejimi sozlamalari mavjud emas"</string>
-    <string name="apn_settings_not_available" msgid="7873729032165324000">"Ushbu foydalanuvchi uchun Ulanish nuqtasi nomi (APN) sozlamalari mavjud emas"</string>
+    <string name="apn_settings_not_available" msgid="7873729032165324000">"Ushbu foydalanuvchi uchun Internetga kirish nuqtasi (APN) sozlamalari mavjud emas"</string>
     <string name="enable_adb" msgid="7982306934419797485">"USB orqali nosozliklarni tuzatish"</string>
     <string name="enable_adb_summary" msgid="4881186971746056635">"USB orqali kompyuterga ulanganda tuzatish rejimi yoqilsin"</string>
     <string name="clear_adb_keys" msgid="4038889221503122743">"USB orqali nosozliklarni tuzatishni taqiqlash"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 55bd08a..7e22881 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -675,6 +675,11 @@
     <!-- Sound & display settings screen, theme setting value to automatically switch between a light- or dark-colored user interface [CHAR LIMIT=30] -->
     <string name="night_mode_auto">Automatic</string>
 
+    <!-- Developer settings: select WebView provider title -->
+    <string name="select_webview_provider_title">WebView implementation</string>
+    <!-- Developer settings: select WebView provider dialog title -->
+    <string name="select_webview_provider_dialog_title">Set WebView implementation</string>
+
     <!-- Developer settings screen, convert userdata to file encryption option name -->
     <string name="convert_to_file_encryption">Convert to file encryption</string>
     <!-- Developer settings screen, convert userdata to file encryption summary when option is available -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/NetworkPolicySerializer.java b/packages/SettingsProvider/src/com/android/providers/settings/NetworkPolicySerializer.java
new file mode 100644
index 0000000..4b87da4
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/NetworkPolicySerializer.java
@@ -0,0 +1,186 @@
+package com.android.providers.settings;
+
+import android.net.NetworkPolicy;
+import android.net.NetworkTemplate;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Backup/Restore Serializer Class for android.net.NetworkPolicy
+ */
+public class NetworkPolicySerializer {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "NetworkPolicySerializer";
+
+    private static final int NULL = 0;
+    private static final int NOT_NULL = 1;
+    /**
+     * Current Version of the Serializer.
+     */
+    private static int STATE_VERSION = 1;
+
+    /**
+     * Marshals an array of NetworkPolicy objects into a byte-array.
+     *
+     * @param policies - NetworkPolicies to be Marshaled
+     * @return byte array
+     */
+
+    public static byte[] marshalNetworkPolicies(NetworkPolicy policies[]) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if (policies != null && policies.length != 0) {
+            DataOutputStream out = new DataOutputStream(baos);
+            try {
+                out.writeInt(STATE_VERSION);
+                out.writeInt(policies.length);
+                for (NetworkPolicy policy : policies) {
+                    byte[] marshaledPolicy = marshalNetworkPolicy(policy);
+                    if (marshaledPolicy != null) {
+                        out.writeByte(NOT_NULL);
+                        out.writeInt(marshaledPolicy.length);
+                        out.write(marshaledPolicy);
+                    } else {
+                        out.writeByte(NULL);
+                    }
+                }
+            } catch (IOException ioe) {
+                Log.e(TAG, "Failed to Convert NetworkPolicies to byte array", ioe);
+                baos.reset();
+            }
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Unmarshals a byte array into an array of NetworkPolicy Objects
+     *
+     * @param data - marshaled NetworkPolicies Array
+     * @return NetworkPolicy[] array
+     */
+    public static NetworkPolicy[] unmarshalNetworkPolicies(byte[] data) {
+        if (data == null || data.length == 0) {
+            return new NetworkPolicy[0];
+        }
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+        try {
+            int version = in.readInt();
+            int length = in.readInt();
+            NetworkPolicy[] policies = new NetworkPolicy[length];
+            for (int i = 0; i < length; i++) {
+                byte isNull = in.readByte();
+                if (isNull == NULL) continue;
+                int byteLength = in.readInt();
+                byte[] policyData = new byte[byteLength];
+                in.read(policyData, 0, byteLength);
+                policies[i] = unmarshalNetworkPolicy(policyData);
+            }
+            return policies;
+        } catch (IOException ioe) {
+            Log.e(TAG, "Failed to Convert byte array to NetworkPolicies", ioe);
+            return new NetworkPolicy[0];
+        }
+    }
+
+    /**
+     * Marshals a NetworkPolicy object into a byte-array.
+     *
+     * @param networkPolicy - NetworkPolicy to be Marshaled
+     * @return byte array
+     */
+    public static byte[] marshalNetworkPolicy(NetworkPolicy networkPolicy) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if (networkPolicy != null) {
+            DataOutputStream out = new DataOutputStream(baos);
+            try {
+                out.writeInt(STATE_VERSION);
+                writeNetworkTemplate(out, networkPolicy.template);
+                out.writeInt(networkPolicy.cycleDay);
+                writeString(out, networkPolicy.cycleTimezone);
+                out.writeLong(networkPolicy.warningBytes);
+                out.writeLong(networkPolicy.limitBytes);
+                out.writeLong(networkPolicy.lastWarningSnooze);
+                out.writeLong(networkPolicy.lastLimitSnooze);
+                out.writeInt(networkPolicy.metered ? 1 : 0);
+                out.writeInt(networkPolicy.inferred ? 1 : 0);
+            } catch (IOException ioe) {
+                Log.e(TAG, "Failed to Convert NetworkPolicy to byte array", ioe);
+                baos.reset();
+            }
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Unmarshals a byte array into a NetworkPolicy Object
+     *
+     * @param data - marshaled NetworkPolicy Object
+     * @return NetworkPolicy Object
+     */
+    public static NetworkPolicy unmarshalNetworkPolicy(byte[] data) {
+        if (data == null || data.length == 0) {
+            return null;
+        }
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+        try {
+            int version = in.readInt();
+            NetworkTemplate template = readNetworkTemplate(in, version);
+            int cycleDay = in.readInt();
+            String cycleTimeZone = readString(in, version);
+            long warningBytes = in.readLong();
+            long limitBytes = in.readLong();
+            long lastWarningSnooze = in.readLong();
+            long lastLimitSnooze = in.readLong();
+            boolean metered = in.readInt() == 1;
+            boolean inferred = in.readInt() == 1;
+            return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes,
+                    lastWarningSnooze, lastLimitSnooze, metered, inferred);
+        } catch (IOException ioe) {
+            Log.e(TAG, "Failed to Convert byte array to NetworkPolicy", ioe);
+            return null;
+        }
+    }
+
+    private static NetworkTemplate readNetworkTemplate(DataInputStream in, int version)
+            throws IOException {
+        byte isNull = in.readByte();
+        if (isNull == NULL) return null;
+        int matchRule = in.readInt();
+        String subscriberId = readString(in, version);
+        String networkId = readString(in, version);
+        return new NetworkTemplate(matchRule, subscriberId, networkId);
+    }
+
+    private static void writeNetworkTemplate(DataOutputStream out, NetworkTemplate template)
+            throws IOException {
+        if (template != null) {
+            out.writeByte(NOT_NULL);
+            out.writeInt(template.getMatchRule());
+            writeString(out, template.getSubscriberId());
+            writeString(out, template.getNetworkId());
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static String readString(DataInputStream in, int version) throws IOException {
+        byte isNull = in.readByte();
+        if (isNull == NOT_NULL) {
+            return in.readUTF();
+        }
+        return null;
+    }
+
+    private static void writeString(DataOutputStream out, String val) throws IOException {
+        if (val != null) {
+            out.writeByte(NOT_NULL);
+            out.writeUTF(val);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 2e96f18..185a03f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -24,6 +24,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.net.NetworkPolicyManager;
 import android.net.Uri;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -81,10 +82,13 @@
     private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
     private static final String KEY_LOCK_SETTINGS = "lock_settings";
+    private static final String KEY_SOFTAP_CONFIG = "softap_config";
+    private static final String KEY_NET_POLICIES = "network_policies";
+
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 4;
+    private static final int STATE_VERSION = 6;
 
     // Slots in the checksum array.  Never insert new items in the middle
     // of this array; new slots must be appended.
@@ -95,22 +99,28 @@
     private static final int STATE_WIFI_CONFIG     = 4;
     private static final int STATE_GLOBAL          = 5;
     private static final int STATE_LOCK_SETTINGS   = 6;
+    private static final int STATE_SOFTAP_CONFIG   = 7;
+    private static final int STATE_NET_POLICIES    = 8;
 
-    private static final int STATE_SIZE            = 7; // The current number of state items
+    private static final int STATE_SIZE            = 9; // The current number of state items
 
     // Number of entries in the checksum array at various version numbers
     private static final int STATE_SIZES[] = {
-        0,
-        4,              // version 1
-        5,              // version 2 added STATE_WIFI_CONFIG
-        6,              // version 3 added STATE_GLOBAL
-        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
+            0,
+            4,              // version 1
+            5,              // version 2 added STATE_WIFI_CONFIG
+            6,              // version 3 added STATE_GLOBAL
+            7,              // version 4 added STATE_LOCK_SETTINGS
+            8,              // version 5 added STATE_SOFTAP_CONFIG
+            STATE_SIZE      // version 6 added STATE_NET_POLICIES
     };
 
     // Versioning of the 'full backup' format
     private static final int FULL_BACKUP_VERSION = 3;
     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
     private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
+    private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
+    private static final int FULL_BACKUP_ADDED_NET_POLICIES = 5; //added the "network_policies" entry
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -119,8 +129,8 @@
     private static final String TAG = "SettingsBackupAgent";
 
     private static final String[] PROJECTION = {
-        Settings.NameValueTable.NAME,
-        Settings.NameValueTable.VALUE
+            Settings.NameValueTable.NAME,
+            Settings.NameValueTable.VALUE
     };
 
     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
@@ -396,7 +406,7 @@
 
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState) throws IOException {
+                         ParcelFileDescriptor newState) throws IOException {
 
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
@@ -405,26 +415,34 @@
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
+        byte[] softApConfigData = getSoftAPConfiguration();
+        byte[] netPoliciesData = getNetworkPolicies();
 
         long[] stateChecksums = readOldChecksums(oldState);
 
         stateChecksums[STATE_SYSTEM] =
-            writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
         stateChecksums[STATE_SECURE] =
-            writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
         stateChecksums[STATE_GLOBAL] =
-            writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
         stateChecksums[STATE_LOCALE] =
-            writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
+                writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI_SUPPLICANT] =
-            writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
-                    wifiSupplicantData, data);
+                writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+                        wifiSupplicantData, data);
         stateChecksums[STATE_WIFI_CONFIG] =
-            writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
-                    data);
+                writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+                        data);
         stateChecksums[STATE_LOCK_SETTINGS] =
-            writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
-                    lockSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+                        lockSettingsData, data);
+        stateChecksums[STATE_SOFTAP_CONFIG] =
+                writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
+                        softApConfigData, data);
+        stateChecksums[STATE_NET_POLICIES] =
+                writeIfChanged(stateChecksums[STATE_NET_POLICIES], KEY_NET_POLICIES,
+                        netPoliciesData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -504,7 +522,7 @@
                             restoredSupplicantData, restoredSupplicantData.length);
                     FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                             FileUtils.S_IRUSR | FileUtils.S_IWUSR |
-                            FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                                    FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                             Process.myUid(), Process.WIFI_UID);
                 }
                 if (restoredWifiConfigFile != null) {
@@ -533,7 +551,7 @@
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode,
-            ParcelFileDescriptor newState) throws IOException {
+                          ParcelFileDescriptor newState) throws IOException {
 
         HashSet<String> movedToGlobal = new HashSet<String>();
         Settings.System.getMovedToGlobalSettings(movedToGlobal);
@@ -561,7 +579,15 @@
                 mWifiRestore.incorporateWifiConfigFile(data);
             } else if (KEY_LOCK_SETTINGS.equals(key)) {
                 restoreLockSettings(data);
-             } else {
+            } else if (KEY_SOFTAP_CONFIG.equals(key)){
+                byte[] softapData = new byte[size];
+                data.readEntityData(softapData, 0, size);
+                restoreSoftApConfiguration(softapData);
+            } else if (KEY_NET_POLICIES.equals(key)) {
+                byte[] netPoliciesData = new byte[size];
+                data.readEntityData(netPoliciesData, 0, size);
+                restoreNetworkPolicies(netPoliciesData);
+            } else {
                 data.skipEntityData();
             }
         }
@@ -589,6 +615,8 @@
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
+        byte[] softApConfigData = getSoftAPConfiguration();
+        byte[] netPoliciesData = getNetworkPolicies();
 
         // Write the data to the staging file, then emit that as our tarfile
         // representation of the backed-up settings.
@@ -623,6 +651,12 @@
             if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
             out.writeInt(lockSettingsData.length);
             out.write(lockSettingsData);
+            if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
+            out.writeInt(softApConfigData.length);
+            out.write(softApConfigData);
+            if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of network policies data");
+            out.writeInt(netPoliciesData.length);
+            out.write(netPoliciesData);
 
             out.flush();    // also flushes downstream
 
@@ -635,7 +669,7 @@
 
     @Override
     public void onRestoreFile(ParcelFileDescriptor data, long size,
-            int type, String domain, String relpath, long mode, long mtime)
+                              int type, String domain, String relpath, long mode, long mtime)
             throws IOException {
         if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
         // Our data is actually a blob of flattened settings data identical to that
@@ -692,7 +726,7 @@
             restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
             FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                     FileUtils.S_IRUSR | FileUtils.S_IWUSR |
-                    FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                            FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                     Process.myUid(), Process.WIFI_UID);
             // retain the previous WIFI state.
             enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
@@ -715,6 +749,26 @@
                 }
             }
 
+            if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF){
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreSoftApConfiguration(buffer);
+                }
+            }
+
+            if (version >= FULL_BACKUP_ADDED_NET_POLICIES){
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreNetworkPolicies(buffer);
+                }
+            }
+
             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
         } else {
             data.close();
@@ -754,7 +808,7 @@
     }
 
     private long writeIfChanged(long oldChecksum, String key, byte[] data,
-            BackupDataOutput output) {
+                                BackupDataOutput output) {
         CRC32 checkSummer = new CRC32();
         checkSummer.update(data);
         long newChecksum = checkSummer.getValue();
@@ -829,7 +883,7 @@
     }
 
     private void restoreSettings(BackupDataInput data, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+                                 HashSet<String> movedToGlobal) {
         byte[] settings = new byte[data.getDataSize()];
         try {
             data.readEntityData(settings, 0, settings.length);
@@ -841,7 +895,7 @@
     }
 
     private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+                                 HashSet<String> movedToGlobal) {
         if (DEBUG) {
             Log.i(TAG, "restoreSettings: " + contentUri);
         }
@@ -1160,6 +1214,30 @@
         }
     }
 
+    private byte[] getSoftAPConfiguration(){
+        WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
+        return WiFiConfigurationSerializer.marshalWifiConfig(wifiManager.getWifiApConfiguration());
+    }
+
+    private void restoreSoftApConfiguration(byte[] data){
+        WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
+        wifiManager.setWifiApConfiguration(WiFiConfigurationSerializer.unmarshalWifiConfig(data));
+    }
+
+    private byte[] getNetworkPolicies(){
+        NetworkPolicyManager networkPolicyManager =
+                (NetworkPolicyManager)getSystemService(NETWORK_POLICY_SERVICE);
+        return NetworkPolicySerializer
+                .marshalNetworkPolicies(networkPolicyManager.getNetworkPolicies());
+    }
+
+    private void restoreNetworkPolicies(byte[] data){
+        NetworkPolicyManager networkPolicyManager =
+                (NetworkPolicyManager)getSystemService(NETWORK_POLICY_SERVICE);
+        networkPolicyManager
+                .setNetworkPolicies(NetworkPolicySerializer.unmarshalNetworkPolicies(data));
+    }
+
     /**
      * Write an int in BigEndian into the byte array.
      * @param out byte array
@@ -1181,8 +1259,7 @@
     }
 
     private int readInt(byte[] in, int pos) {
-        int result =
-                ((in[pos    ] & 0xFF) << 24) |
+        int result =    ((in[pos    ] & 0xFF) << 24) |
                 ((in[pos + 1] & 0xFF) << 16) |
                 ((in[pos + 2] & 0xFF) <<  8) |
                 ((in[pos + 3] & 0xFF) <<  0);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
new file mode 100644
index 0000000..f9f1d3f
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.settings;
+
+import android.net.IpConfiguration;
+import android.net.LinkAddress;
+import android.net.ProxyInfo;
+import android.net.StaticIpConfiguration;
+import android.net.wifi.WifiConfiguration;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.BitSet;
+
+
+/**
+ * Backup/Restore Serializer Class for com.android.net.wifi.WifiConfiguration
+ */
+public class WiFiConfigurationSerializer {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "WiFiConfigSerializer";
+
+    private static final int NULL = 0;
+    private static final int NOT_NULL = 1;
+    /**
+     * Current Version of the Serializer.
+     */
+    private static int STATE_VERSION = 1;
+
+
+    /**
+     * Marshals a WifiConfig object into a byte-array.
+     *
+     * @param wifiConfig - WifiConfiguration to be Marshalled
+     * @return byte array
+     */
+
+    public static byte[] marshalWifiConfig(WifiConfiguration wifiConfig) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if(wifiConfig != null) {
+            DataOutputStream out = new DataOutputStream(baos);
+            try {
+                out.writeInt(STATE_VERSION);
+                out.writeInt(wifiConfig.networkId);
+                out.writeInt(wifiConfig.status);
+                out.writeInt(wifiConfig.disableReason);
+                writeString(out, wifiConfig.SSID);
+                writeString(out, wifiConfig.BSSID);
+                out.writeInt(wifiConfig.apBand);
+                out.writeInt(wifiConfig.apChannel);
+                writeString(out, wifiConfig.autoJoinBSSID);
+                writeString(out, wifiConfig.FQDN);
+                writeString(out, wifiConfig.providerFriendlyName);
+                out.writeInt(wifiConfig.roamingConsortiumIds.length);
+                for (long id : wifiConfig.roamingConsortiumIds) {
+                    out.writeLong(id);
+                }
+                writeString(out, wifiConfig.preSharedKey);
+                for (String wepKey : wifiConfig.wepKeys) {
+                    writeString(out, wepKey);
+                }
+                out.writeInt(wifiConfig.wepTxKeyIndex);
+                out.writeInt(wifiConfig.priority);
+                out.writeInt(wifiConfig.hiddenSSID ? 1 : 0);
+                out.writeInt(wifiConfig.requirePMF ? 1 : 0);
+                writeString(out, wifiConfig.updateIdentifier);
+
+                writeBitSet(out, wifiConfig.allowedKeyManagement);
+                writeBitSet(out, wifiConfig.allowedProtocols);
+                writeBitSet(out, wifiConfig.allowedAuthAlgorithms);
+                writeBitSet(out, wifiConfig.allowedPairwiseCiphers);
+                writeBitSet(out, wifiConfig.allowedGroupCiphers);
+
+
+                //IpConfiguration
+                writeIpConfiguration(out, wifiConfig.getIpConfiguration());
+
+                writeString(out, wifiConfig.dhcpServer);
+                writeString(out, wifiConfig.defaultGwMacAddress);
+                out.writeInt(wifiConfig.autoJoinStatus);
+                out.writeInt(wifiConfig.selfAdded ? 1 : 0);
+                out.writeInt(wifiConfig.didSelfAdd ? 1 : 0);
+                out.writeInt(wifiConfig.validatedInternetAccess ? 1 : 0);
+                out.writeInt(wifiConfig.ephemeral ? 1 : 0);
+                out.writeInt(wifiConfig.creatorUid);
+                out.writeInt(wifiConfig.lastConnectUid);
+                out.writeInt(wifiConfig.lastUpdateUid);
+                writeString(out, wifiConfig.creatorName);
+                writeString(out, wifiConfig.lastUpdateName);
+                out.writeLong(wifiConfig.blackListTimestamp);
+                out.writeLong(wifiConfig.lastConnectionFailure);
+                out.writeLong(wifiConfig.lastRoamingFailure);
+                out.writeInt(wifiConfig.lastRoamingFailureReason);
+                out.writeLong(wifiConfig.roamingFailureBlackListTimeMilli);
+                out.writeLong(wifiConfig.numConnectionFailures);
+                out.writeLong(wifiConfig.numIpConfigFailures);
+                out.writeInt(wifiConfig.numAuthFailures);
+                out.writeInt(wifiConfig.numScorerOverride);
+                out.writeInt(wifiConfig.numScorerOverrideAndSwitchedNetwork);
+                out.writeInt(wifiConfig.numAssociation);
+                out.writeInt(wifiConfig.numUserTriggeredWifiDisableLowRSSI);
+                out.writeInt(wifiConfig.numUserTriggeredWifiDisableBadRSSI);
+                out.writeInt(wifiConfig.numUserTriggeredWifiDisableNotHighRSSI);
+                out.writeInt(wifiConfig.numTicksAtLowRSSI);
+                out.writeInt(wifiConfig.numTicksAtBadRSSI);
+                out.writeInt(wifiConfig.numTicksAtNotHighRSSI);
+                out.writeInt(wifiConfig.numUserTriggeredJoinAttempts);
+                out.writeInt(wifiConfig.autoJoinUseAggressiveJoinAttemptThreshold);
+                out.writeInt(wifiConfig.autoJoinBailedDueToLowRssi ? 1 : 0);
+                out.writeInt(wifiConfig.userApproved);
+                out.writeInt(wifiConfig.numNoInternetAccessReports);
+                out.writeInt(wifiConfig.noInternetAccessExpected ? 1 : 0);
+            } catch (IOException ioe) {
+                Log.e(TAG, "Failed to Convert WifiConfiguration to byte array", ioe);
+                baos.reset();
+            }
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Unmarshals a byte array into a WifiConfig Object
+     *
+     * @param data - marshalled WifiConfig Object
+     * @return WifiConfiguration Object
+     */
+
+    public static WifiConfiguration unmarshalWifiConfig(byte[] data) {
+        if (data == null ||  data.length == 0) {
+            return null;
+        }
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+        WifiConfiguration config = new WifiConfiguration();
+        try {
+            int version = in.readInt();
+
+            config.networkId = in.readInt();
+            config.status = in.readInt();
+            config.disableReason = in.readInt();
+            config.SSID = readString(in, version);
+            config.BSSID = readString(in, version);
+            config.apBand = in.readInt();
+            config.apChannel = in.readInt();
+            config.autoJoinBSSID = readString(in, version);
+            config.FQDN = readString(in, version);
+            config.providerFriendlyName = readString(in, version);
+            int numRoamingConsortiumIds = in.readInt();
+            config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
+            for (int i = 0; i < numRoamingConsortiumIds; i++) {
+                config.roamingConsortiumIds[i] = in.readLong();
+            }
+            config.preSharedKey = readString(in, version);
+            for (int i = 0; i < config.wepKeys.length; i++) {
+                config.wepKeys[i] = readString(in, version);
+            }
+            config.wepTxKeyIndex = in.readInt();
+            config.priority = in.readInt();
+            config.hiddenSSID = in.readInt() != 0;
+            config.requirePMF = in.readInt() != 0;
+            config.updateIdentifier = readString(in, version);
+
+            config.allowedKeyManagement = readBitSet(in, version);
+            config.allowedProtocols = readBitSet(in, version);
+            config.allowedAuthAlgorithms = readBitSet(in, version);
+            config.allowedPairwiseCiphers = readBitSet(in, version);
+            config.allowedGroupCiphers = readBitSet(in, version);
+
+            //Not backed-up because EnterpriseConfig involves
+            //Certificates which are device specific.
+            //config.enterpriseConfig = new WifiEnterpriseConfig();
+
+            config.setIpConfiguration(readIpConfiguration(in, version));
+
+
+            config.dhcpServer = readString(in, version);
+            config.defaultGwMacAddress = readString(in, version);
+            config.autoJoinStatus = in.readInt();
+            config.selfAdded = in.readInt() != 0;
+            config.didSelfAdd = in.readInt() != 0;
+            config.validatedInternetAccess = in.readInt() != 0;
+            config.ephemeral = in.readInt() != 0;
+            config.creatorUid = in.readInt();
+            config.lastConnectUid = in.readInt();
+            config.lastUpdateUid = in.readInt();
+            config.creatorName = readString(in, version);
+            config.lastUpdateName = readString(in, version);
+            config.blackListTimestamp = in.readLong();
+            config.lastConnectionFailure = in.readLong();
+            config.lastRoamingFailure = in.readLong();
+            config.lastRoamingFailureReason = in.readInt();
+            config.roamingFailureBlackListTimeMilli = in.readLong();
+            config.numConnectionFailures = in.readInt();
+            config.numIpConfigFailures = in.readInt();
+            config.numAuthFailures = in.readInt();
+            config.numScorerOverride = in.readInt();
+            config.numScorerOverrideAndSwitchedNetwork = in.readInt();
+            config.numAssociation = in.readInt();
+            config.numUserTriggeredWifiDisableLowRSSI = in.readInt();
+            config.numUserTriggeredWifiDisableBadRSSI = in.readInt();
+            config.numUserTriggeredWifiDisableNotHighRSSI = in.readInt();
+            config.numTicksAtLowRSSI = in.readInt();
+            config.numTicksAtBadRSSI = in.readInt();
+            config.numTicksAtNotHighRSSI = in.readInt();
+            config.numUserTriggeredJoinAttempts = in.readInt();
+            config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
+            config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
+            config.userApproved = in.readInt();
+            config.numNoInternetAccessReports = in.readInt();
+            config.noInternetAccessExpected = in.readInt() != 0;
+        } catch (IOException ioe) {
+            Log.e(TAG, "Failed to convert byte array to WifiConfiguration object", ioe);
+            return null;
+        }
+        return config;
+    }
+
+    private static ProxyInfo readProxyInfo(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        String host = readString(in, version);
+        int port = in.readInt();
+        String exclusionList = readString(in, version);
+        return new ProxyInfo(host, port, exclusionList);
+    }
+
+    private static void writeProxyInfo(DataOutputStream out, ProxyInfo proxyInfo) throws IOException {
+        if (proxyInfo != null) {
+            out.writeByte(NOT_NULL);
+            writeString(out, proxyInfo.getHost());
+            out.writeInt(proxyInfo.getPort());
+            writeString(out, proxyInfo.getExclusionListAsString());
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static InetAddress readInetAddress(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        InetAddress address = null;
+        int addressLength = in.readInt();
+        if (addressLength < 1) return address;
+        byte[] addressBytes = new byte[addressLength];
+        in.read(addressBytes, 0, addressLength);
+        try {
+            address = InetAddress.getByAddress(addressBytes);
+        } catch (UnknownHostException unknownHostException) {
+            return null;
+        }
+        return address;
+    }
+
+    private static void writeInetAddress(DataOutputStream out, InetAddress address) throws IOException {
+        if (address.getAddress() != null) {
+            out.writeByte(NOT_NULL);
+            out.writeInt(address.getAddress().length);
+            out.write(address.getAddress(), 0, address.getAddress().length);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static LinkAddress readLinkAddress(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        InetAddress address = readInetAddress(in, version);
+        int prefixLength = in.readInt();
+        int flags = in.readInt();
+        int scope = in.readInt();
+        return new LinkAddress(address, prefixLength, flags, scope);
+    }
+
+    private static void writeLinkAddress(DataOutputStream out, LinkAddress address) throws IOException {
+        if (address != null) {
+            out.writeByte(NOT_NULL);
+            writeInetAddress(out, address.getAddress());
+            out.writeInt(address.getPrefixLength());
+            out.writeInt(address.getFlags());
+            out.writeInt(address.getScope());
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static StaticIpConfiguration readStaticIpConfiguration(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
+        staticIpConfiguration.ipAddress = readLinkAddress(in, version);
+        staticIpConfiguration.gateway = readInetAddress(in, version);
+        int dnsServersLength = in.readInt();
+        for (int i = 0; i < dnsServersLength; i++) {
+            staticIpConfiguration.dnsServers.add(readInetAddress(in, version));
+        }
+        staticIpConfiguration.domains = readString(in, version);
+        return staticIpConfiguration;
+    }
+
+    private static void writeStaticIpConfiguration(DataOutputStream out, StaticIpConfiguration staticIpConfiguration) throws IOException {
+        if (staticIpConfiguration != null) {
+            out.writeByte(NOT_NULL);
+            writeLinkAddress(out, staticIpConfiguration.ipAddress);
+            writeInetAddress(out, staticIpConfiguration.gateway);
+            out.writeInt(staticIpConfiguration.dnsServers.size());
+            for (InetAddress inetAddress : staticIpConfiguration.dnsServers) {
+                writeInetAddress(out, inetAddress);
+            }
+            writeString(out, staticIpConfiguration.domains);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static IpConfiguration readIpConfiguration(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        IpConfiguration ipConfiguration = new IpConfiguration();
+        String tmp = readString(in, version);
+        ipConfiguration.ipAssignment = tmp == null ? null : IpConfiguration.IpAssignment.valueOf(tmp);
+        tmp = readString(in, version);
+        ipConfiguration.proxySettings = tmp == null ? null : IpConfiguration.ProxySettings.valueOf(tmp);
+        ipConfiguration.staticIpConfiguration = readStaticIpConfiguration(in, version);
+        ipConfiguration.httpProxy = readProxyInfo(in, version);
+        return ipConfiguration;
+    }
+
+
+    private static void writeIpConfiguration(DataOutputStream out, IpConfiguration ipConfiguration) throws IOException {
+        if (ipConfiguration != null) {
+            out.writeByte(NOT_NULL);
+            writeString(out, ipConfiguration.ipAssignment != null ? ipConfiguration.ipAssignment.name() : null);
+            writeString(out, ipConfiguration.proxySettings != null ? ipConfiguration.proxySettings.name() : null);
+            writeStaticIpConfiguration(out, ipConfiguration.staticIpConfiguration);
+            writeProxyInfo(out, ipConfiguration.httpProxy);
+        } else {
+            out.writeByte(NULL);
+        }
+
+    }
+
+    private static String readString(DataInputStream in, int version) throws IOException {
+        byte isNull = in.readByte();
+        if (isNull == NOT_NULL) {
+            return in.readUTF();
+        }
+        return null;
+    }
+
+    private static void writeString(DataOutputStream out, String val) throws IOException {
+        if (val != null) {
+            out.writeByte(NOT_NULL);
+            out.writeUTF(val);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static BitSet readBitSet(DataInputStream in, int version) throws IOException {
+        byte isNull = in.readByte();
+        if (isNull == NOT_NULL) {
+            int length = in.readInt();
+            byte[] bytes = new byte[length];
+            in.read(bytes, 0, length);
+            return BitSet.valueOf(bytes);
+        }
+        return new BitSet();
+    }
+
+    private static void writeBitSet(DataOutputStream out, BitSet val) throws IOException {
+        if (val != null) {
+            out.writeByte(NOT_NULL);
+            byte[] byteArray = val.toByteArray();
+            out.writeInt(byteArray.length);
+            out.write(byteArray);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+}
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index ef863e7..f278967 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -5,7 +5,10 @@
 # Note we statically link SettingsState to do some unit tests.  It's not accessible otherwise
 # because this test is not an instrumentation test. (because the target runs in the system process.)
 LOCAL_SRC_FILES := $(call all-subdir-java-files) \
-    ../src/com/android/providers/settings/SettingsState.java
+    ../src/com/android/providers/settings/SettingsState.java \
+    ../src/com/android/providers/settings/WiFiConfigurationSerializer.java \
+    ../src/com/android/providers/settings/NetworkPolicySerializer.java
+
 
 LOCAL_PACKAGE_NAME := SettingsProviderTest
 
@@ -13,4 +16,4 @@
 
 LOCAL_CERTIFICATE := platform
 
-include $(BUILD_PACKAGE)
\ No newline at end of file
+include $(BUILD_PACKAGE)
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/NetworkPolicySerializerTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/NetworkPolicySerializerTest.java
new file mode 100644
index 0000000..1986596
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/NetworkPolicySerializerTest.java
@@ -0,0 +1,117 @@
+package com.android.providers.settings;
+
+import android.net.NetworkPolicy;
+import android.net.NetworkTemplate;
+import android.test.AndroidTestCase;
+
+import java.util.Random;
+
+/**
+ * Tests for NetworkPolicySerializer
+ */
+public class NetworkPolicySerializerTest extends AndroidTestCase {
+    static Random sRandom = new Random();
+
+    public void testMarshallAndUnmarshalNetworkPolicy() {
+        NetworkPolicy policy = getDummyNetworkPolicy();
+        byte[] data = NetworkPolicySerializer.marshalNetworkPolicy(policy);
+        assertNotNull("Got Null data from marshal", data);
+        assertFalse("Got back an empty byte[] from marshal", data.length == 0);
+
+        NetworkPolicy unmarshaled = NetworkPolicySerializer.unmarshalNetworkPolicy(data);
+        assertNotNull("Got Null data from unmarshaled", unmarshaled);
+        assertTrue("NetworkPolicy Marshall and Unmarshal Failed!", policy.equals(unmarshaled));
+    }
+
+    public void testMarshallNetworkPolicyEdgeCases() {
+        byte[] data = NetworkPolicySerializer.marshalNetworkPolicy(null);
+        assertNotNull("NetworkPolicy marshal returned null. Expected: byte[0]", data);
+        assertEquals("NetworkPolicy marshal returned incomplete byte array. Expected: byte[0]",
+                data.length, 0);
+    }
+
+    public void testUnmarshallNetworkPolicyEdgeCases() {
+        NetworkPolicy policy = NetworkPolicySerializer.unmarshalNetworkPolicy(null);
+        assertNull("Non null NetworkPolicy returned for null byte[] input", policy);
+
+        policy = NetworkPolicySerializer.unmarshalNetworkPolicy(new byte[0]);
+        assertNull("Non null NetworkPolicy returned for empty byte[] input", policy);
+
+        policy = NetworkPolicySerializer.unmarshalNetworkPolicy(new byte[]{10, 20, 30, 40, 50, 60});
+        assertNull("Non null NetworkPolicy returned for incomplete byte[] input", policy);
+    }
+
+    public void testMarshallAndUnmarshalNetworkPolicies() {
+        NetworkPolicy[] policies = getDummyNetworkPolicies(5);
+        byte[] data = NetworkPolicySerializer.marshalNetworkPolicies(policies);
+        assertNotNull("Got Null data from marshal", data);
+        assertFalse("Got back an empty byte[] from marshal", data.length == 0);
+
+        NetworkPolicy[] unmarshaled = NetworkPolicySerializer.unmarshalNetworkPolicies(data);
+        assertNotNull("Got Null data from unmarshaled", unmarshaled);
+        try {
+            for (int i = 0; i < policies.length; i++) {
+                assertTrue("NetworkPolicies Marshall and Unmarshal Failed!",
+                        policies[i].equals(unmarshaled[i]));
+            }
+        } catch (NullPointerException npe) {
+            assertTrue("Some policies were not marshaled/unmarshaled correctly", false);
+        }
+    }
+
+    public void testMarshallNetworkPoliciesEdgeCases() {
+        byte[] data = NetworkPolicySerializer.marshalNetworkPolicies(null);
+        assertNotNull("NetworkPolicies marshal returned null!", data);
+        assertEquals("NetworkPolicies marshal returned incomplete byte array", data.length, 0);
+
+        data = NetworkPolicySerializer.marshalNetworkPolicies(new NetworkPolicy[0]);
+        assertNotNull("NetworkPolicies marshal returned null for empty NetworkPolicy[]", data);
+        assertEquals("NetworkPolicies marshal returned incomplete byte array for empty NetworkPolicy[]"
+                , data.length, 0);
+    }
+
+    public void testUnmarshalNetworkPoliciesEdgeCases() {
+        NetworkPolicy[] policies = NetworkPolicySerializer.unmarshalNetworkPolicies(null);
+        assertNotNull("NetworkPolicies unmarshal returned null for null input. Expected: byte[0] ",
+                policies);
+        assertEquals("Non Empty NetworkPolicy[] returned for null input Expected: byte[0]",
+                policies.length, 0);
+
+        policies = NetworkPolicySerializer.unmarshalNetworkPolicies(new byte[0]);
+        assertNotNull("NetworkPolicies unmarshal returned null for empty byte[] input. Expected: byte[0]",
+                policies);
+        assertEquals("Non Empty NetworkPolicy[] returned for empty byte[] input. Expected: byte[0]",
+                policies.length, 0);
+
+        policies = NetworkPolicySerializer.unmarshalNetworkPolicies(new byte[]{10, 20, 30, 40, 50, 60});
+        assertNotNull("NetworkPolicies unmarshal returned null for incomplete byte[] input. " +
+                "Expected: byte[0] ", policies);
+        assertEquals("Non Empty NetworkPolicy[] returned for incomplete byte[] input Expected: byte[0]",
+                policies.length, 0);
+
+    }
+
+    private NetworkPolicy[] getDummyNetworkPolicies(int num) {
+        NetworkPolicy[] policies = new NetworkPolicy[num];
+        for (int i = 0; i < num; i++) {
+            policies[i] = getDummyNetworkPolicy();
+        }
+        return policies;
+    }
+
+    private NetworkPolicy getDummyNetworkPolicy() {
+        NetworkTemplate template = new NetworkTemplate(NetworkTemplate.MATCH_MOBILE_ALL, "subId",
+                "GoogleGuest");
+        int cycleDay = sRandom.nextInt();
+        String cycleTimezone = "timezone";
+        long warningBytes = sRandom.nextLong();
+        long limitBytes = sRandom.nextLong();
+        long lastWarningSnooze = sRandom.nextLong();
+        long lastLimitSnooze = sRandom.nextLong();
+        boolean metered = sRandom.nextInt() % 2 == 0;
+        boolean inferred = sRandom.nextInt() % 2 == 0;
+        return new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes,
+                lastWarningSnooze, lastLimitSnooze, metered, inferred);
+    }
+
+}
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index aafeb24..c5b4144 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
-    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Мүчүлүштүктөр тууралуу билдирүү өндүрүлүүдө"</string>
+    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Мүчүлүштүктөр тууралуу билдирүү түзүлүүдө"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Ката тууралуу билдирүү түзүлдү"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Ката жөнүндө кабар менен бөлүшүү үчүн солго серпип коюңуз"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Ката тууралуу билдирүүңүздү жөнөтүш үчүн, тийиңиз"</string>
@@ -25,5 +25,5 @@
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бул билдирүү кийин көрсөтүлсүн"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоолор"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
-    <string name="bugreport_unnamed" msgid="2800582406842092709">"аты жок"</string>
+    <string name="bugreport_unnamed" msgid="2800582406842092709">"аталышы жок"</string>
 </resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index 4491add..db8b5dc 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
-    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan pepijat sedang dijanakan"</string>
+    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan pepijat sedang dijana"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Leret ke kiri untuk berkongsi laporan pepijat anda"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 1decb98..03aef3c 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -25,5 +25,5 @@
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यो सन्देश अर्को पटक देखाउनुहोस्"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फाइल पढ्न सकिएन"</string>
-    <string name="bugreport_unnamed" msgid="2800582406842092709">"(बेनामी)"</string>
+    <string name="bugreport_unnamed" msgid="2800582406842092709">"(नामविहीन)"</string>
 </resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 417c444..757538c 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
-    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"O relatório de erro está a ser gerado"</string>
+    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"O relatório de erro está a ser criado"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de erros capturado"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Deslizar rapidamente para a esquerda para partilhar o seu relatório de erros"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para partilhar o relatório de erros"</string>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index 2ae832b..5dc5953 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Оболочка"</string>
-    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Создание отчета об ошибке"</string>
+    <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Создание отчета об ошибке…"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчет об ошибке сохранен"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Проведите влево, чтобы отправить отчет"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Нажмите, чтобы отправить отчет об ошибках"</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 78e373b..e902589 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -66,7 +66,7 @@
 import android.widget.Toast;
 
 /**
- * Service used to keep progress of bug reports processes ({@code dumpstate}).
+ * Service used to keep progress of bugreport processes ({@code dumpstate}).
  * <p>
  * The workflow is:
  * <ol>
@@ -84,21 +84,25 @@
  * <li>{@link BugreportReceiver} receives the intent and delegates it to this service, which in
  * turn:
  * <ol>
- * <li>Updates the system notification so user can share the bug report.
+ * <li>Updates the system notification so user can share the bugreport.
  * <li>Stops monitoring that {@code dumpstate} process.
  * <li>Stops itself if it doesn't have any process left to monitor.
  * </ol>
  * </ol>
  */
 public class BugreportProgressService extends Service {
-    private static final String TAG = "Shell";
+    static final String TAG = "Shell";
     private static final boolean DEBUG = false;
 
     private static final String AUTHORITY = "com.android.shell";
 
+    // External intents sent by dumpstate.
     static final String INTENT_BUGREPORT_STARTED = "android.intent.action.BUGREPORT_STARTED";
     static final String INTENT_BUGREPORT_FINISHED = "android.intent.action.BUGREPORT_FINISHED";
+
+    // Internal intents used on notification actions.
     static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
+    static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
 
     static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
     static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
@@ -111,7 +115,7 @@
     private static final int MSG_POLL = 2;
 
     /** Polling frequency, in milliseconds. */
-    private static final long POLLING_FREQUENCY = 500;
+    static final long POLLING_FREQUENCY = 2000;
 
     /** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */
     private static final long INACTIVITY_TIMEOUT = 3 * DateUtils.MINUTE_IN_MILLIS;
@@ -169,10 +173,16 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        writer.printf("Monitored dumpstate processes: \n");
         synchronized (mProcesses) {
-            for (int i = 0; i < mProcesses.size(); i++) {
-              writer.printf("\t%s\n", mProcesses.valueAt(i));
+            final int size = mProcesses.size();
+            if (size == 0) {
+                writer.printf("No monitored processes");
+                return;
+            }
+            writer.printf("Monitored dumpstate processes\n");
+            writer.printf("-----------------------------\n");
+            for (int i = 0; i < size; i++) {
+              writer.printf("%s\n", mProcesses.valueAt(i));
             }
         }
     }
@@ -180,7 +190,6 @@
     private final class ServiceHandler extends Handler {
         public ServiceHandler(Looper looper) {
             super(looper);
-            poll();
         }
 
         @Override
@@ -196,25 +205,24 @@
                 return;
             }
 
-            // At this point it's handling onStartCommand(), whose intent contains the extras
-            // originally received by BugreportReceiver.
+            // At this point it's handling onStartCommand(), with the intent passed as an Extra.
             if (!(msg.obj instanceof Intent)) {
                 // Sanity check.
                 Log.e(TAG, "Internal error: invalid msg.obj: " + msg.obj);
                 return;
             }
             final Parcelable parcel = ((Intent) msg.obj).getParcelableExtra(EXTRA_ORIGINAL_INTENT);
-            if (!(parcel instanceof Intent)) {
-                // Sanity check.
-                Log.e(TAG, "Internal error: msg.obj is missing extra " + EXTRA_ORIGINAL_INTENT);
-                return;
+            final Intent intent;
+            if (parcel instanceof Intent) {
+                // The real intent was passed to BugreportReceiver, which delegated to the service.
+                intent = (Intent) parcel;
+            } else {
+                intent = (Intent) msg.obj;
             }
-
-            final Intent intent = (Intent) parcel;
             final String action = intent.getAction();
-            int pid = intent.getIntExtra(EXTRA_PID, 0);
-            int max = intent.getIntExtra(EXTRA_MAX, -1);
-            String name = intent.getStringExtra(EXTRA_NAME);
+            final int pid = intent.getIntExtra(EXTRA_PID, 0);
+            final int max = intent.getIntExtra(EXTRA_MAX, -1);
+            final String name = intent.getStringExtra(EXTRA_NAME);
 
             if (DEBUG) Log.v(TAG, "action: " + action + ", name: " + name + ", pid: " + pid
                     + ", max: "+ max);
@@ -224,14 +232,18 @@
                         stopSelfWhenDone();
                         return;
                     }
+                    poll();
                     break;
                 case INTENT_BUGREPORT_FINISHED:
-                    if (pid == -1) {
+                    if (pid == 0) {
                         // Shouldn't happen, unless BUGREPORT_FINISHED is received from a legacy,
                         // out-of-sync dumpstate process.
                         Log.w(TAG, "Missing " + EXTRA_PID + " on intent " + intent);
                     }
-                    stopProgress(pid, intent);
+                    onBugreportFinished(pid, intent);
+                    break;
+                case INTENT_BUGREPORT_SHARE:
+                    shareBugreport(pid);
                     break;
                 case INTENT_BUGREPORT_CANCEL:
                     cancel(pid);
@@ -247,6 +259,8 @@
             if (pollProgress()) {
                 // Keep polling...
                 sendEmptyMessageDelayed(MSG_POLL, POLLING_FREQUENCY);
+            } else {
+                Log.i(TAG, "Stopped polling");
             }
         }
     }
@@ -283,7 +297,7 @@
     }
 
     /**
-     * Updates the system notification for a given bug report.
+     * Updates the system notification for a given bugreport.
      */
     private void updateProgress(BugreportInfo info) {
         if (info.max <= 0 || info.progress < 0) {
@@ -296,14 +310,8 @@
         nf.setMinimumFractionDigits(2);
         nf.setMaximumFractionDigits(2);
         final String percentText = nf.format((double) info.progress / info.max);
-
-        final Intent cancelIntent = new Intent(context, BugreportReceiver.class);
-        cancelIntent.setAction(INTENT_BUGREPORT_CANCEL);
-        cancelIntent.putExtra(EXTRA_PID, info.pid);
-        final Action cancelAction = new Action.Builder(null,
-                context.getString(com.android.internal.R.string.cancel),
-                PendingIntent.getBroadcast(context, info.pid, cancelIntent,
-                        PendingIntent.FLAG_CANCEL_CURRENT)).build();
+        final Action cancelAction = new Action.Builder(null, context.getString(
+                com.android.internal.R.string.cancel), newCancelIntent(context, info)).build();
 
         final String title = context.getString(R.string.bugreport_in_progress_title);
         final String name =
@@ -327,9 +335,19 @@
     }
 
     /**
-     * Finalizes the progress on a given process and sends the finished intent.
+     * Creates a {@link PendingIntent} for a notification action used to cancel a bugreport.
      */
-    private void stopProgress(int pid, Intent intent) {
+    private static PendingIntent newCancelIntent(Context context, BugreportInfo info) {
+        final Intent intent = new Intent(INTENT_BUGREPORT_CANCEL);
+        intent.setClass(context, BugreportProgressService.class);
+        intent.putExtra(EXTRA_PID, info.pid);
+        return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    /**
+     * Finalizes the progress on a given bugreport and cancel its notification.
+     */
+    private void stopProgress(int pid) {
         synchronized (mProcesses) {
             if (mProcesses.indexOfKey(pid) < 0) {
                 Log.w(TAG, "PID not watched: " + pid);
@@ -340,11 +358,6 @@
         }
         if (DEBUG) Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
         NotificationManager.from(getApplicationContext()).cancel(TAG, pid);
-        if (intent != null) {
-            // Bug report finished fine: send a new, different notification.
-            if (DEBUG) Log.v(TAG, "stopProgress(" + pid + "): finish bug report");
-            onBugreportFinished(pid, intent);
-        }
     }
 
     /**
@@ -353,7 +366,7 @@
     private void cancel(int pid) {
         Log.i(TAG, "Cancelling PID " + pid + " on user's request");
         SystemProperties.set(CTL_STOP, BUGREPORT_SERVICE);
-        stopProgress(pid, null);
+        stopProgress(pid);
     }
 
     /**
@@ -363,11 +376,19 @@
      */
     private boolean pollProgress() {
         synchronized (mProcesses) {
-            if (mProcesses.size() == 0) {
+            final int total = mProcesses.size();
+            if (total == 0) {
                 Log.d(TAG, "No process to poll progress.");
             }
-            for (int i = 0; i < mProcesses.size(); i++) {
+            int activeProcesses = 0;
+            for (int i = 0; i < total; i++) {
                 final int pid = mProcesses.keyAt(i);
+                final BugreportInfo info = mProcesses.valueAt(i);
+                if (info.finished) {
+                    if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+                    continue;
+                }
+                activeProcesses++;
                 final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
                 final int progress = SystemProperties.getInt(progressKey, 0);
                 if (progress == 0) {
@@ -375,7 +396,6 @@
                     continue;
                 }
                 final int max = SystemProperties.getInt(DUMPSTATE_PREFIX + pid + MAX_SUFFIX, 0);
-                final BugreportInfo info = mProcesses.valueAt(i);
                 final boolean maxChanged = max > 0 && max != info.max;
                 final boolean progressChanged = progress > 0 && progress != info.progress;
 
@@ -397,11 +417,12 @@
                     if (inactiveTime >= INACTIVITY_TIMEOUT) {
                         Log.w(TAG, "No progress update for process " + pid + " since "
                                 + info.getFormattedLastUpdate());
-                        stopProgress(info.pid, null);
+                        stopProgress(info.pid);
                     }
                 }
             }
-            return true;
+            if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
+            return activeProcesses > 0;
         }
     }
 
@@ -421,37 +442,46 @@
 
     private void onBugreportFinished(int pid, Intent intent) {
         final Context context = getApplicationContext();
-        final Configuration conf = context.getResources().getConfiguration();
-        final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
-        final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+        BugreportInfo info;
+        synchronized (mProcesses) {
+            info = mProcesses.get(pid);
+            if (info == null) {
+                // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED
+                Log.v(TAG, "Creating info for untracked pid " + pid);
+                info = new BugreportInfo(context, pid);
+                mProcesses.put(pid, info);
+            }
+            info.bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+            info.screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+        }
 
+        final Configuration conf = context.getResources().getConfiguration();
         if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
-            triggerLocalNotification(context, pid, bugreportFile, screenshotFile);
+            triggerLocalNotification(context, info);
         }
     }
 
     /**
      * Responsible for triggering a notification that allows the user to start a "share" intent with
-     * the bug report. On watches we have other methods to allow the user to start this intent
+     * the bugreport. On watches we have other methods to allow the user to start this intent
      * (usually by triggering it on another connected device); we don't need to display the
      * notification in this case.
      */
-    private static void triggerLocalNotification(final Context context, final int pid,
-            final File bugreportFile, final File screenshotFile) {
-        if (!bugreportFile.exists() || !bugreportFile.canRead()) {
-            Log.e(TAG, "Could not read bugreport file " + bugreportFile);
+    private static void triggerLocalNotification(final Context context, final BugreportInfo info) {
+        if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
+            Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
             Toast.makeText(context, context.getString(R.string.bugreport_unreadable_text),
                     Toast.LENGTH_LONG).show();
             return;
         }
 
-        boolean isPlainText = bugreportFile.getName().toLowerCase().endsWith(".txt");
+        boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
         if (!isPlainText) {
             // Already zipped, send it right away.
-            sendBugreportNotification(context, pid, bugreportFile, screenshotFile);
+            sendBugreportNotification(context, info);
         } else {
             // Asynchronously zip the file first, then send it.
-            sendZippedBugreportNotification(context, pid, bugreportFile, screenshotFile);
+            sendZippedBugreportNotification(context, info);
         }
     }
 
@@ -498,17 +528,27 @@
     }
 
     /**
-     * Sends a bugreport notitication.
+     * Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
+     * intent, but issuing a warning dialog the first time.
      */
-    private static void sendBugreportNotification(Context context, int pid, File bugreportFile,
-            File screenshotFile) {
+    private void shareBugreport(int pid) {
+        final Context context = getApplicationContext();
+        final BugreportInfo info;
+        synchronized (mProcesses) {
+            info = mProcesses.get(pid);
+            if (info == null) {
+                // Should not happen, so log if it does...
+                Log.e(TAG, "INTERNAL ERROR: no info for PID " + pid + ": " + mProcesses);
+                return;
+            }
+        }
         // Files are kept on private storage, so turn into Uris that we can
         // grant temporary permissions for.
-        final Uri bugreportUri = getUri(context, bugreportFile);
-        final Uri screenshotUri = getUri(context, screenshotFile);
+        final Uri bugreportUri = getUri(context, info.bugreportFile);
+        final Uri screenshotUri = getUri(context, info.screenshotFile);
 
-        Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
-        Intent notifIntent;
+        final Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
+        final Intent notifIntent;
 
         // Send through warning dialog by default
         if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
@@ -518,32 +558,48 @@
         }
         notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
+        // Send the share intent...
+        context.startActivity(notifIntent);
+
+        // ... and stop watching this process.
+        stopProgress(pid);
+    }
+
+    /**
+     * Sends a notitication indicating the bugreport has finished so use can share it.
+     */
+    private static void sendBugreportNotification(Context context, BugreportInfo info) {
+        final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
+        shareIntent.setClass(context, BugreportProgressService.class);
+        shareIntent.setAction(INTENT_BUGREPORT_SHARE);
+        shareIntent.putExtra(EXTRA_PID, info.pid);
+
         final String title = context.getString(R.string.bugreport_finished_title);
         final Notification.Builder builder = new Notification.Builder(context)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(context.getString(R.string.bugreport_finished_text))
-                .setContentIntent(PendingIntent.getActivity(
-                        context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT))
-                .setAutoCancel(true)
+                .setContentIntent(PendingIntent.getService(context, 0, shareIntent,
+                        PendingIntent.FLAG_CANCEL_CURRENT))
+                .setDeleteIntent(newCancelIntent(context, info))
                 .setLocalOnly(true)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
 
-        NotificationManager.from(context).notify(TAG, pid, builder.build());
+        NotificationManager.from(context).notify(TAG, info.pid, builder.build());
     }
 
     /**
      * Sends a zipped bugreport notification.
      */
     private static void sendZippedBugreportNotification(final Context context,
-            final int pid, final File bugreportFile, final File screenshotFile) {
+            final BugreportInfo info) {
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                File zippedFile = zipBugreport(bugreportFile);
-                sendBugreportNotification(context, pid, zippedFile, screenshotFile);
+                info.bugreportFile = zipBugreport(info.bugreportFile);
+                sendBugreportNotification(context, info);
                 return null;
             }
         }.execute();
@@ -629,31 +685,31 @@
     }
 
     /**
-     * Information about a bug report process while its in progress.
+     * Information about a bugreport process while its in progress.
      */
     private static final class BugreportInfo {
         private final Context context;
 
         /**
-         * {@code pid} of the {@code dumpstate} process generating the bug report.
+         * {@code pid} of the {@code dumpstate} process generating the bugreport.
          */
         final int pid;
 
         /**
-         * Name of the bug report, will be used to rename the final files.
+         * Name of the bugreport, will be used to rename the final files.
          * <p>
-         * Initial value is the bug report filename reported by {@code dumpstate}, but user can
+         * Initial value is the bugreport filename reported by {@code dumpstate}, but user can
          * change it later to a more meaningful name.
          */
         String name;
 
         /**
-         * Maximum progress of the bug report generation.
+         * Maximum progress of the bugreport generation.
          */
         int max;
 
         /**
-         * Current progress of the bug report generation.
+         * Current progress of the bugreport generation.
          */
         int progress;
 
@@ -662,6 +718,24 @@
          */
         long lastUpdate = System.currentTimeMillis();
 
+        /**
+         * Path of the main bugreport file.
+         */
+        File bugreportFile;
+
+        /**
+         * Path of the screenshot file.
+         */
+        File screenshotFile;
+
+        /**
+         * Whether dumpstate sent an intent informing it has finished.
+         */
+        boolean finished;
+
+        /**
+         * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
+         */
         BugreportInfo(Context context, int pid, String name, int max) {
             this.context = context;
             this.pid = pid;
@@ -669,6 +743,15 @@
             this.max = max;
         }
 
+        /**
+         * Constructor for untracked bugreports - typically called upon receiving BUGREPORT_FINISHED
+         * without a previous call to BUGREPORT_STARTED.
+         */
+        BugreportInfo(Context context, int pid) {
+            this(context, pid, null, 0);
+            this.finished = true;
+        }
+
         String getFormattedLastUpdate() {
             return DateUtils.formatDateTime(context, lastUpdate,
                     DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME);
@@ -677,8 +760,10 @@
         @Override
         public String toString() {
             final float percent = ((float) progress * 100 / max);
-            return "Progress for " + name + " (pid=" + pid + "): " + progress + "/" + max
-                    + " (" + percent + "%) Last update: " + getFormattedLastUpdate();
+            return "pid: " + pid + ", name: " + name + ", finished: " + finished
+                    + "\n\tfile: " + bugreportFile + "\n\tscreenshot: " + screenshotFile
+                    + "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
+                    + "\n\tlast_update: " + getFormattedLastUpdate();
         }
     }
 }
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index 5133162..b818343 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -19,6 +19,7 @@
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
 import static com.android.shell.BugreportProgressService.EXTRA_ORIGINAL_INTENT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
+import static com.android.shell.BugreportProgressService.TAG;
 import static com.android.shell.BugreportProgressService.getFileExtra;
 
 import java.io.File;
@@ -29,6 +30,7 @@
 import android.os.AsyncTask;
 import android.os.FileUtils;
 import android.text.format.DateUtils;
+import android.util.Log;
 
 /**
  * Receiver that handles finished bugreports, usually by attaching them to an
@@ -63,6 +65,10 @@
             return;
         }
         final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+        if (bugreportFile == null || !bugreportFile.exists()) {
+            Log.e(TAG, "Not deleting old files because file " + bugreportFile + " doesn't exist");
+            return;
+        }
         final PendingResult result = goAsync();
         new AsyncTask<Void, Void, Void>() {
             @Override
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 0e31cdf..1f4d749 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -29,6 +29,7 @@
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -40,9 +41,12 @@
 import java.util.zip.ZipOutputStream;
 
 import libcore.io.Streams;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
 import android.app.Instrumentation;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -51,6 +55,7 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
 import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
@@ -71,23 +76,30 @@
  * <p>
  * <strong>NOTE</strong>: these tests only work if the device is unlocked.
  */
+@LargeTest
 public class BugreportReceiverTest extends InstrumentationTestCase {
-
     private static final String TAG = "BugreportReceiverTest";
 
     // Timeout for UI operations, in milliseconds.
-    private static final int TIMEOUT = 1000;
+    private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
 
-    private static final String ROOT_DIR = "/data/data/com.android.shell/files/bugreports";
+    private static final String BUGREPORTS_DIR = "bugreports";
     private static final String BUGREPORT_FILE = "test_bugreport.txt";
     private static final String ZIP_FILE = "test_bugreport.zip";
-    private static final String PLAIN_TEXT_PATH = ROOT_DIR + "/" + BUGREPORT_FILE;
-    private static final String ZIP_PATH = ROOT_DIR + "/" + ZIP_FILE;
-    private static final String SCREENSHOT_PATH = ROOT_DIR + "/test_screenshot.png";
+    private static final String SCREENSHOT_FILE = "test_screenshot.png";
 
     private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n";
     private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n";
 
+    private static final int PID = 42;
+    private static final String PROGRESS_PROPERTY = "dumpstate.42.progress";
+    private static final String MAX_PROPERTY = "dumpstate.42.max";
+    private static final String NAME = "BUG, Y U NO REPORT?";
+
+    private String mPlainTextPath;
+    private String mZipPath;
+    private String mScreenshotPath;
+
     private Context mContext;
     private UiBot mUiBot;
     private CustomActionSendMultipleListener mListener;
@@ -98,39 +110,39 @@
         mContext = instrumentation.getTargetContext();
         mUiBot = new UiBot(UiDevice.getInstance(instrumentation), TIMEOUT);
         mListener = ActionSendMultipleConsumerActivity.getListener(mContext);
+
         cancelExistingNotifications();
+
+        mPlainTextPath = getPath(BUGREPORT_FILE);
+        mZipPath = getPath(ZIP_FILE);
+        mScreenshotPath = getPath(SCREENSHOT_FILE);
+        createTextFile(mPlainTextPath, BUGREPORT_CONTENT);
+        createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
+        createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
+
         BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
     }
 
     public void testFullWorkflow() throws Exception {
-        final String name = "BUG, Y U NO REPORT?";
-        // TODO: call method to remove property instead
-        SystemProperties.set("dumpstate.42.progress", "0");
-        SystemProperties.set("dumpstate.42.max", "0");
+        resetProperties();
+        sendBugreportStarted(1000);
 
-        Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
-        intent.putExtra(EXTRA_PID, 42);
-        intent.putExtra(EXTRA_NAME, name);
-        intent.putExtra(EXTRA_MAX, 1000);
-        mContext.sendBroadcast(intent);
+        assertProgressNotification(NAME, "0.00%");
 
-        assertProgressNotification(name, "0.00%");
+        SystemProperties.set(PROGRESS_PROPERTY, "108");
+        assertProgressNotification(NAME, "10.80%");
 
-        SystemProperties.set("dumpstate.42.progress", "108");
-        assertProgressNotification(name, "10.80%");
+        SystemProperties.set(PROGRESS_PROPERTY, "500");
+        assertProgressNotification(NAME, "50.00%");
 
-        SystemProperties.set("dumpstate.42.progress", "500");
-        assertProgressNotification(name, "50.00%");
+        SystemProperties.set(MAX_PROPERTY, "2000");
+        assertProgressNotification(NAME, "25.00%");
 
-        SystemProperties.set("dumpstate.42.max", "2000");
-        assertProgressNotification(name, "25.00%");
-
-        createTextFile(PLAIN_TEXT_PATH, BUGREPORT_CONTENT);
-        createTextFile(SCREENSHOT_PATH, SCREENSHOT_CONTENT);
-        Bundle extras = sendBugreportFinishedIntent(42, PLAIN_TEXT_PATH, SCREENSHOT_PATH);
+        Bundle extras =
+                sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
 
-        // TODO: assert service is down
+        assertServiceNotRunning();
     }
 
     public void testBugreportFinished_withWarning() throws Exception {
@@ -138,11 +150,8 @@
         BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
 
         // Send notification and click on share.
-        createTextFile(PLAIN_TEXT_PATH, BUGREPORT_CONTENT);
-        Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
-        intent.putExtra(EXTRA_BUGREPORT, PLAIN_TEXT_PATH);
-        mContext.sendBroadcast(intent);
-        mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title));
+        sendBugreportFinished(null, mPlainTextPath, null);
+        acceptBugreport();
 
         // Handle the warning
         mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
@@ -164,28 +173,22 @@
     }
 
     public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception {
-        createTextFile(PLAIN_TEXT_PATH, BUGREPORT_CONTENT);
-        createTextFile(SCREENSHOT_PATH, SCREENSHOT_CONTENT);
-        Bundle extras = sendBugreportFinishedIntent(PLAIN_TEXT_PATH, SCREENSHOT_PATH);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
     }
 
     public void testBugreportFinished_zippedBugreportAndScreenshot() throws Exception {
-        createZipFile(ZIP_PATH, BUGREPORT_FILE, BUGREPORT_CONTENT);
-        createTextFile(SCREENSHOT_PATH, SCREENSHOT_CONTENT);
-        Bundle extras = sendBugreportFinishedIntent(ZIP_PATH, SCREENSHOT_PATH);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
     }
 
     public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception {
-        createTextFile(PLAIN_TEXT_PATH, BUGREPORT_CONTENT);
-        Bundle extras = sendBugreportFinishedIntent(PLAIN_TEXT_PATH, null);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, null);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
     }
 
     public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception {
-        createZipFile(ZIP_PATH, BUGREPORT_FILE, BUGREPORT_CONTENT);
-        Bundle extras = sendBugreportFinishedIntent(ZIP_PATH, null);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, null);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
     }
 
@@ -209,17 +212,67 @@
         mUiBot.getObject(percent);
     }
 
+    void resetProperties() {
+        // TODO: call method to remove property instead
+        SystemProperties.set(PROGRESS_PROPERTY, "0");
+        SystemProperties.set(MAX_PROPERTY, "0");
+    }
+
+    /**
+     * Sends a "bugreport started" intent with the default values.
+     */
+    private void sendBugreportStarted(int max) {
+        Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
+        intent.putExtra(EXTRA_PID, PID);
+        intent.putExtra(EXTRA_NAME, NAME);
+        intent.putExtra(EXTRA_MAX, max);
+        mContext.sendBroadcast(intent);
+    }
+
     /**
      * Sends a "bugreport finished" intent and waits for the result.
      *
-     * @return extras sent to the bugreport finished consumer.
+     * @return extras sent in the shared intent.
      */
-    private Bundle sendBugreportFinishedIntent(String bugreportPath, String screenshotPath) {
-        return sendBugreportFinishedIntent(null, bugreportPath, screenshotPath);
+    private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath,
+            String screenshotPath) {
+        return sendBugreportFinishedAndGetSharedIntent(null, bugreportPath, screenshotPath);
     }
 
-    private Bundle sendBugreportFinishedIntent(Integer pid, String bugreportPath,
+    /**
+     * Sends a "bugreport finished" intent and waits for the result.
+     *
+     * @return extras sent in the shared intent.
+     */
+    private Bundle sendBugreportFinishedAndGetSharedIntent(Integer pid, String bugreportPath,
             String screenshotPath) {
+        sendBugreportFinished(pid, bugreportPath, screenshotPath);
+        return acceptBugreportAndGetSharedIntent();
+    }
+
+    /**
+     * Accepts the notification to share the finished bugreport and waits for the result.
+     *
+     * @return extras sent in the shared intent.
+     */
+    private Bundle acceptBugreportAndGetSharedIntent() {
+        acceptBugreport();
+        mUiBot.chooseActivity(UI_NAME);
+        return mListener.getExtras();
+    }
+
+    /**
+     * Accepts the notification to share the finished bugreport.
+     */
+    private void acceptBugreport() {
+        mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title));
+    }
+
+    /**
+     * Sends a "bugreport finished" intent.
+     *
+     */
+    private void sendBugreportFinished(Integer pid, String bugreportPath, String screenshotPath) {
         Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
         if (pid != null) {
             intent.putExtra(EXTRA_PID, pid);
@@ -232,10 +285,6 @@
         }
 
         mContext.sendBroadcast(intent);
-
-        mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title));
-        mUiBot.chooseActivity(UI_NAME);
-        return mListener.getExtras();
     }
 
     /**
@@ -306,6 +355,22 @@
         fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
     }
 
+    private void assertServiceNotRunning() {
+        String service = BugreportProgressService.class.getName();
+        assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
+    }
+
+    private boolean isServiceRunning(String name) {
+        ActivityManager manager = (ActivityManager) mContext
+                .getSystemService(Context.ACTIVITY_SERVICE);
+        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+            if (service.service.getClassName().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static void createTextFile(String path, String content) throws IOException {
         Log.v(TAG, "createFile(" + path + ")");
         try (Writer writer = new BufferedWriter(new OutputStreamWriter(
@@ -325,4 +390,16 @@
             zos.closeEntry();
         }
     }
+
+    private String getPath(String file) {
+        File rootDir = new ContextWrapper(mContext).getFilesDir();
+        File dir = new File(rootDir, BUGREPORTS_DIR);
+        if (!dir.exists()) {
+            Log.i(TAG, "Creating directory " + dir);
+            assertTrue("Could not create directory " + dir, dir.mkdir());
+        }
+        String path = new File(dir, file).getAbsolutePath();
+        Log.v(TAG, "Path for '" + file + "': " + path);
+        return path;
+    }
 }
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index 5e8bab1..c871727 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -118,11 +118,22 @@
     // TODO: UI Automator should provide such logic.
     public void chooseActivity(String name) {
         // First check if the activity is the default option.
-        String shareText = String.format("Share with %s", name);
+        String shareText = "Share with " + name;
+        Log.v(TAG, "Waiting for ActivityChooser text: '" + shareText + "'");
         boolean gotIt = mDevice.wait(Until.hasObject(By.text(shareText)), mTimeout);
 
         if (gotIt) {
             Log.v(TAG, "Found activity " + name + ", it's the default action");
+            // Clicks the "Just Once" button.
+            gotIt = mDevice
+                    .wait(Until.hasObject(By.res("android", "button_once")), mTimeout);
+            assertTrue("'Just Once' button not visible yet", gotIt);
+
+            UiObject justOnce = mDevice
+                    .findObject(new UiSelector().resourceId("android:id/button_once"));
+            assertTrue("'Just Once' button not found", justOnce.exists());
+
+            click(justOnce, "Just Once");
         } else {
             // Since it's not, need to find it in the scrollable list...
             Log.v(TAG, "Activity " + name + " is not default action");
@@ -139,16 +150,5 @@
             // ... then select it.
             click(activity, name);
         }
-
-        // Then clicks the "Just Once" button.
-        gotIt = mDevice
-                .wait(Until.hasObject(By.res("android", "button_once")), mTimeout);
-        assertTrue("'Just Once' button not visible yet", gotIt);
-
-        UiObject justOnce = mDevice
-                .findObject(new UiSelector().resourceId("android:id/button_once"));
-        assertTrue("'Just Once' button not found", justOnce.exists());
-
-        click(justOnce, "Just Once");
     }
 }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2e65656..51b84f5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -136,6 +136,9 @@
             android:protectionLevel="signature" />
     <uses-permission android:name="com.android.systemui.permission.SELF" />
 
+    <!-- Adding Quick Settings tiles -->
+    <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/res/color/remote_input_send.xml b/packages/SystemUI/res/color/remote_input_send.xml
new file mode 100644
index 0000000..fe2ffaa
--- /dev/null
+++ b/packages/SystemUI/res/color/remote_input_send.xml
@@ -0,0 +1,21 @@
+<?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
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true" android:color="@android:color/white" />
+    <item android:color="#4dffffff" /> <!-- 30% white -->
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/remote_input_text.xml b/packages/SystemUI/res/color/remote_input_text.xml
new file mode 100644
index 0000000..11ce0b7
--- /dev/null
+++ b/packages/SystemUI/res/color/remote_input_text.xml
@@ -0,0 +1,21 @@
+<?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
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true" android:color="@android:color/white" />
+    <item android:color="#99ffffff" /> <!-- 60% white -->
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/header_dot.xml b/packages/SystemUI/res/drawable/header_dot.xml
new file mode 100644
index 0000000..568a9c2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/header_dot.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 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.
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+    <solid 
+        android:color="#FFFFFF"/>
+
+    <size 
+        android:width="3dp"
+        android:height="3dp"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/recents_freeform_workspace_bg.xml b/packages/SystemUI/res/drawable/recents_freeform_workspace_bg.xml
new file mode 100644
index 0000000..5f9341c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_freeform_workspace_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners android:topLeftRadius="@dimen/recents_task_view_rounded_corners_radius"
+             android:topRightRadius="@dimen/recents_task_view_rounded_corners_radius"/>
+    <solid android:color="#00000000" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index d52c274..c9dbc79 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -16,75 +16,77 @@
 -->
 
 <com.android.systemui.statusbar.NotificationGuts
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/notification_guts"
-    android:visibility="gone"
-    android:clickable="true"
-    android:gravity="top|start"
-    >
-    <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="@android:dimen/notification_large_icon_height"
-            android:orientation="horizontal"
-            >
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/notification_guts"
+        android:visibility="gone"
+        android:clickable="true"
+        android:gravity="top|start"
+        android:orientation="vertical"
+        android:paddingEnd="8dp"
+        android:background="@color/notification_guts_text_color" >
 
-        <ImageView android:id="@android:id/icon"
-               android:layout_width="@android:dimen/notification_large_icon_width"
-               android:layout_height="@android:dimen/notification_large_icon_height"
-               android:layout_weight="0"
-               android:padding="8dp"
-               android:scaleType="centerInside"
-               />
-        <LinearLayout
+    <!-- header -->
+    <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="start|center_vertical"
-            android:orientation="vertical"
-            android:paddingStart="8dp"
-            android:paddingEnd="8dp"
-            android:layout_weight="1"
-            >
-            <TextView
-                    android:id="@+id/pkgname"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical|start"
-                    android:layout_weight="1"
-                    android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
-                    android:textColor="@color/notification_guts_title_color"
-                    />
-            <DateTimeView
-                    android:id="@+id/timestamp"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:layout_gravity="center_vertical|start"
-                    android:textAppearance="@*android:style/TextAppearance.Material.Notification.Time"
-                    android:textColor="@color/notification_guts_text_color"
-                    />
-            <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:id="@+id/debug_info"
-                    android:layout_weight="0"
-                    android:textAppearance="@*android:style/TextAppearance.Material.Notification.Time"
-                    android:layout_gravity="bottom|start"
-                    android:visibility="gone"
-                    android:textColor="@color/notification_guts_text_color"
-                    />
-        </LinearLayout>
+            android:paddingStart="@*android:dimen/notification_content_margin_start"
+            android:paddingTop="8dp"
+            android:paddingBottom="16dp" >
 
-        <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-                 android:id="@+id/notification_inspect_app_provided_settings"
-                 android:layout_width="52dp"
-                 android:layout_height="match_parent"
-                 android:layout_weight="0"
-                 android:gravity="center"
-                 android:src="@drawable/ic_settings"
-                 android:visibility="gone"
-                />
+        <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/notification_guts_header"
+                android:orientation="vertical"
+                android:layout_gravity="center_vertical|start"
+                android:layout_marginEnd="52dp">
+
+                <LinearLayout
+                        android:id="@+id/notification_guts_app_details"
+                        android:orientation="horizontal"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:clipChildren="false"
+                        android:layout_gravity="start|top"
+                        android:gravity="center_vertical"
+                        >
+
+                    <ImageView
+                            android:id="@android:id/icon"
+                            android:layout_width="18dp"
+                            android:layout_height="18dp"
+                            android:layout_marginEnd="3dp"
+                            android:src="@android:drawable/arrow_down_float" />
+                    <TextView
+                            android:id="@+id/pkgname"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:textAppearance="@android:style/TextAppearance.Material.Notification.Info"
+                            android:layout_marginStart="3dp"
+                            android:layout_marginEnd="4dp"
+                            android:textColor="@color/notification_guts_title_color" />
+                    <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:id="@+id/debug_info"
+                            android:layout_weight="0"
+                            android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
+                            android:layout_gravity="bottom|start"
+                            android:visibility="gone"
+                            android:textColor="#ffffff" />
+                </LinearLayout>
+
+                <TextView
+                        android:id="@+id/topic_details"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
+                        android:textColor="@color/notification_guts_text_color"
+                        android:layout_alignParentBottom="true"
+                        android:layout_alignParentStart="true" />
+            </LinearLayout>
 
         <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
                 android:id="@+id/notification_inspect_item"
@@ -92,8 +94,73 @@
                 android:layout_height="match_parent"
                 android:layout_weight="0"
                 android:gravity="center"
+                android:layout_gravity="center_vertical|end"
                 android:contentDescription="@string/status_bar_notification_inspect_item_title"
-                android:src="@drawable/ic_info"
-                />
+                android:src="@drawable/ic_settings" />
+    </FrameLayout>
+    <!-- Importance slider -->
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:paddingStart="@*android:dimen/notification_content_margin_start"
+            android:orientation="vertical"
+            android:clickable="false"
+            android:focusable="false"
+            android:paddingBottom="8dip">
+        <TextView
+                android:id="@+id/title"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                android:textColor="@color/notification_guts_text_color"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal"
+                android:text="@*android:string/notification_importance_title"/>
+
+        <TextView
+                android:id="@+id/summary"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_alignStart="@android:id/title"
+                android:textAlignment="viewStart"
+                android:textAppearance="@android:style/TextAppearance.Material.Body1"
+                android:textColor="@color/notification_guts_title_color"
+                android:maxLines="3"
+                android:minLines="2" />
+
+        <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingTop="6dp" >
+
+            <ImageView
+                    android:id="@+id/low_importance"
+                    android:src="@android:drawable/ic_menu_close_clear_cancel"
+                    android:layout_gravity="center_vertical|start"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp" />
+
+            <SeekBar
+                    android:id="@+id/seekbar"
+                    android:layout_marginStart="24dp"
+                    android:layout_marginEnd="24dp"
+                    android:layout_gravity="center_vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:focusable="true"
+                    android:background="#00ffffff"
+                    android:thumbTint="@android:color/white"
+                    android:progressTint="@android:color/white" />
+
+            <ImageView
+                    android:id="@+id/max_importance"
+                    android:src="@android:drawable/ic_popup_reminder"
+                    android:layout_gravity="center_vertical|end"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"/>
+
+        </FrameLayout>
     </LinearLayout>
 </com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 1873168..bb37b83 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -19,7 +19,6 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="@drawable/qs_background_primary"
-        android:paddingTop="8dp"
         android:paddingBottom="8dp"
         android:elevation="2dp">
 
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 8124eb7..a995ec7 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -33,16 +33,6 @@
     android:focusable="true"
     >
 
-    <com.android.systemui.qs.QuickQSPanel
-        android:id="@+id/quick_qs_panel"
-        android:background="#0000"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_alignParentEnd="true"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layout_marginEnd="12dp" />
-
     <LinearLayout
         android:id="@+id/expanded_group"
         android:layout_width="wrap_content"
@@ -52,7 +42,8 @@
         android:clipToPadding="false"
         android:orientation="horizontal"
         android:layout_alignParentEnd="true"
-        android:layout_marginEnd="12dp">
+        android:layout_marginTop="30dp"
+        android:layout_marginEnd="16dp">
 
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
             android:id="@+id/settings_button_container"
@@ -87,48 +78,76 @@
             android:tint="@android:color/white" />
     </LinearLayout>
 
-    <FrameLayout
-        android:id="@+id/date_group"
+    <TextView
+        android:id="@+id/header_emergency_calls_only"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
+        android:paddingTop="8dp"
+        android:visibility="gone"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
+        android:text="@*android:string/emergency_calls_only"
+        android:singleLine="true"
+        android:gravity="center_vertical" />
+
+    <LinearLayout
+        android:id="@+id/date_time_group"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
-        android:layout_alignParentBottom="true">
-        <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentTop="true"
+        android:orientation="horizontal">
+
+        <include layout="@layout/split_clock_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="16dp"
+            android:layout_marginTop="2dp"
+            android:id="@+id/clock" />
+
+        <com.android.systemui.statusbar.policy.DateView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="6dp"
+            android:layout_marginTop="8dp"
+            android:layout_alignParentTop="true"
+            android:drawableStart="@drawable/header_dot"
+            android:drawablePadding="6dp"
             android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+            android:textSize="@dimen/qs_time_collapsed_size"
+            systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
+
+        <com.android.systemui.statusbar.AlphaOptimizedButton
+            android:id="@+id/alarm_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:drawablePadding="6dp"
+            android:drawableStart="@drawable/ic_access_alarms_small"
+            android:textColor="#64ffffff"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-            android:layout_below="@id/clock"
-            systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm"
-            />
-    </FrameLayout>
+            android:minHeight="36dp"
+            android:paddingStart="6dp"
+            android:background="?android:attr/selectableItemBackground"
+            android:visibility="gone" />
+    </LinearLayout>
 
-    <include layout="@layout/split_clock_view"
-        android:layout_width="wrap_content"
+    <com.android.systemui.qs.QuickQSPanel
+        android:id="@+id/quick_qs_panel"
+        android:background="#0000"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:layout_above="@id/date_group"
-        android:id="@+id/clock"
-        />
-
-    <com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_toEndOf="@id/date_group"
-        android:layout_marginBottom="4dp"
-        android:drawablePadding="6dp"
-        android:drawableStart="@drawable/ic_access_alarms_small"
-        android:textColor="#64ffffff"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-        android:paddingEnd="6dp"
-        android:paddingStart="6dp"
-        android:paddingTop="16dp"
-        android:paddingBottom="16dp"
-        android:background="?android:attr/selectableItemBackground"
-        android:visibility="gone"
-        />
+        android:layout_marginTop="30dp"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
+        android:layout_alignParentEnd="true"
+        android:clipChildren="false"
+        android:clipToPadding="false" />
 
     <include
         android:id="@+id/qs_detail_header"
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 2c010dd..16ff14c 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -33,12 +33,6 @@
         android:layout_height="match_parent">
     </com.android.systemui.recents.views.RecentsView>
 
-    <!-- Empty View -->
-    <ViewStub android:id="@+id/empty_view_stub"
-           android:layout="@layout/recents_empty"
-           android:layout_width="match_parent"
-           android:layout_height="match_parent" />
-
     <!-- History View -->
     <ViewStub android:id="@+id/history_view_stub"
            android:layout="@layout/recents_history"
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_history_button.xml
index 601c5ed..8c96fc6 100644
--- a/packages/SystemUI/res/layout/recents_history_button.xml
+++ b/packages/SystemUI/res/layout/recents_history_button.xml
@@ -26,5 +26,4 @@
     android:shadowDx="0"
     android:shadowDy="2"
     android:shadowRadius="5"
-    android:fontFamily="sans-serif-medium"
-    android:visibility="invisible" />
\ No newline at end of file
+    android:fontFamily="sans-serif-medium" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 74092c1..83cfc76 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -36,7 +36,8 @@
             android:paddingEnd="12dp"
             android:gravity="start|center_vertical"
             android:textAppearance="?android:attr/textAppearance"
-            android:textColor="#deffffff"
+            android:textColor="@color/remote_input_text"
+            android:textColorHint="@color/remote_input_hint"
             android:textSize="16sp"
             android:background="@null"
             android:singleLine="true"
@@ -58,8 +59,8 @@
                 android:paddingBottom="12dp"
                 android:id="@+id/remote_input_send"
                 android:src="@drawable/ic_send"
-                android:tint="@android:color/white"
-                android:tintMode="src_atop"
+                android:tint="@color/remote_input_send"
+                android:tintMode="src_in"
                 android:background="@drawable/ripple_drawable" />
 
         <ProgressBar
diff --git a/packages/SystemUI/res/layout/split_clock_view.xml b/packages/SystemUI/res/layout/split_clock_view.xml
index d1269da..ae5136f 100644
--- a/packages/SystemUI/res/layout/split_clock_view.xml
+++ b/packages/SystemUI/res/layout/split_clock_view.xml
@@ -27,6 +27,7 @@
         android:layout_height="wrap_content"
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:textSize="@dimen/qs_time_collapsed_size"
         />
     <TextClock
         android:id="@+id/am_pm_view"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f3e7cfe..a08c9ca 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Luitoestel stil."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Werkmodus"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Maak <xliff:g id="APP">%s</xliff:g> toe."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwerp."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle onlangse programme is toegemaak."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobiele warmkol afgeskakel."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiele warmkol aangeskakel."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Uitsaai van skerm gestaak."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Werkmodus is af."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Werkmodus is aan."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Werkmodus is afgeskakel."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Werkmodus is aangeskakel."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skermhelderheid"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data is laat wag"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> gebruik"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g>-limiet"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Jou onlangse skerms verskyn hier"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skermvaspen"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Weier"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is die volumedialoog"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Raak om die oorspronklike terug te stel."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Jy gebruik tans jou werkprofiel"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Stelsel-UI-ontvanger"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Wys persentasie van ingebedde battery"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 838a4eb..4591f24 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"የስልክ ጥሪ ፀጥታ።"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"የሥራ ሁነታ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> አስወግድ።"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ተሰናብቷል::"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ሁሉም የቅርብ ጊዜ ማመልከቻዎች ተሰናብተዋል።"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"የተንቀሳቃሽ ስልክ መገናኛ ነጥብ ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"የተንቀሳቃሽ ስልክ መገናኛ ነጥብ በርቷል።"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ማያ ገጽ መውሰድ ቆሟል።"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"የሥራ ሁነታ ጠፍቷል።"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"የሥራ ሁነታ በርቷል።"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"የሥራ ሁነታ ጠፍቷል።"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"የሥራ ሁነታ በርቷል።"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ብሩህነት ያሳዩ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2ጂ-3ጂ ውሂብ ላፍታ ቆሟል"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ጥቅም ላይ ውሏል"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ገደብ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"የሥራ ሁነታ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"የቅርብ ጊዜ ማያ ገጾችዎ እዚህ ይታያሉ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ማያ ገጽ መሰካት"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ከልክል"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> የድምጽ መጠን መገናኛው ነው"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"የመጀመሪያውን ወደነበረበት ለመመለስ ይንኩ።"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"፣ "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"የስራ መገለጫዎን እየተጠቀሙ ነው"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"የስርዓት በይነገጽ መቃኛ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"የተቀላቀለ የባትሪ አጠቃቀም መቶኛ አሳይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 2789ffa..beeb923 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -165,8 +165,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"رنين صامت."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"وضع العمل"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"إزالة <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"تمت إزالة <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"تم تجاهل كل التطبيقات المستخدمة مؤخرًا."</string>
@@ -218,14 +217,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"تم إيقاف نقطة اتصال الجوّال."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"تم تشغيل نقطة اتصال الجوّال."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"توقف إرسال الشاشة."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"وضع العمل معطَّل."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"وضع العمل قيد التشغيل."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"تم تعطيل وضع العمل."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"تم تشغيل وضع العمل."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"سطوع الشاشة"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"بيانات شبكات الجيل الثاني والثالث متوقفة مؤقتًا"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
@@ -303,8 +298,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> مستخدم"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"قيد <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"تحذير <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"وضع العمل"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"تظهر شاشاتك المعروضة مؤخرًا هنا"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"تثبيت الشاشة"</string>
@@ -419,8 +413,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"رفض"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> هو مربع حوار مستوى الصوت"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"المس لاستعادة الإعداد الأصلي."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"، "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"أنت تستخدم ملفك الشخصي للعمل"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"أداة ضبط واجهة مستخدم النظام"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"عرض نسبة البطارية المدمجة"</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 652f71c..b2026a8 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Zəngvuran səssiz."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"İş rejimi"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> kənarlaşdırın."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> çıxarıldı."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Bütün son tətbiqlər kənarlaşdırıldı."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobil hotspot deaktivdir."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil hotspot aktivdir."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekran yayımı dayandırıldı."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"İş rejimi deaktivdir."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"İş rejimi aktivdir."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"İş rejimi sönülüdür."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"İş rejimi yanılıdır."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G məlumatlarına fasilə verildi"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> işlənib"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> limit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> xəbərdarlığı"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"İş rejimi"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Tətbiq haqqında"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sancağı"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rədd et"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> proqramı səs səviyyəsi dialoqudur"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Orijinalı bərpa etmək üçün toxun."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"İş profilinizi istifadə edirsiniz"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Daxil batareya faizini göstərin"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 0bbdbe9..91a5c4c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Звънът е заглушен."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Работен режим"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отхвърляне на <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложението <xliff:g id="APP">%s</xliff:g> е отхвърлено."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Всички скорошни приложения са отхвърлени."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобилната точка за достъп се изключи."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилната точка за достъп се включи."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Предаването на съдържанието от екрана спря."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Работният режим е изключен."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Работният режим е включен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Работният режим е изключен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Работният режим е включен."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркост на екрана"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Данните от 2G – 3G са поставени на пауза"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Използвано: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничение от <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Работен режим"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Скорошните ви екрани се показват тук"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"фиксиране на екрана"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Отказване"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> изпълнява ролята на диалоговия прозорец за силата на звука"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Докоснете, за да възстановите оригинала."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Използвате служебния си потребителски профил"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Тунер на системния потребителски интерфейс"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Показване на процента на вградената батерия"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index e1c3d5e..1c79542 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"রিং বাজানো বন্ধ করুন৷"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"কাজের মোড"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> খারিজ করুন।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> খারিজ করা হয়েছে৷"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"সমস্ত সাম্প্রতিক অ্যাপ্লিকেশন খারিজ করা হয়েছে।"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"মোবাইল হটস্পট বন্ধ হয়েছে।"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"মোবাইল হটস্পট চালু হয়েছে।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"স্ক্রীন কাস্ট করা থেমেছে।"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"কাজের মোড বন্ধ আছে"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"কাজের মোড চালু আছে"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"কাজের মোড বন্ধ আছে।"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"কাজের মোড চালু আছে"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"প্রদর্শনের উজ্জ্বলতা"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ডেটা বিরতি দেওয়া হয়েছে"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ব্যবহৃত হয়েছে"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"সীমা <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"কাজের মোড"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"আপনার সাম্প্রতিক স্ক্রীনগুলো এখানে দেখা যাবে"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"অ্যাপ্লিকেশানের তথ্য"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"স্ক্রীন পিন করা"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"প্রত্যাখ্যান করুন"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> হল ভলিউম ডায়লগ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"আসলটি পুনঃস্থাপন করতে স্পর্শ করুন৷"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"আপনি আপনার কাজের প্রোফাইল ব্যবহার করছেন"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"সিস্টেম UI টিউনার"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"এম্বেড করা ব্যাটারির শতকরা হার দেখায়"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index e361ed0..1fc41a4 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Mode silenci."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Mode de feina"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignora <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"S\'ha omès <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"S\'han descartat totes les aplicacions recents."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"El punt d\'accés mòbil està desactivat."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"El punt d\'accés mòbil està activat."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"S\'ha aturat l\'emissió de la pantalla."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"El mode de feina està desactivat."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"El mode de feina està activat."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"S\'ha desactivat el mode de feina."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"S\'ha activat el mode de feina."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillantor de la pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Les dades 2G-3G estan aturades"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Utilitzats: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode de feina"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Aquí es mostren les teves pantalles recents."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixació de pantalla"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denega"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> és el diàleg de volum"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca per restaurar l\'original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estàs utilitzant el perfil professional"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Personalitzador d\'interfície d\'usuari"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra el percentatge de la bateria inserit"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 11a9bbe..f405f10 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Tiché vyzvánění."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Pracovní režim"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zavřít aplikaci <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikace <xliff:g id="APP">%s</xliff:g> byla odebrána."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všechny naposledy použité aplikace byly odstraněny."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobile hotspot je vypnutý."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Odesílání obrazovky zastaveno."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Pracovní režim vypnutý"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Pracovní režim zapnutý"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Pracovní režim je vypnutý."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Pracovní režim je zapnutý."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeje"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G a 3G jsou pozastavena"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Využito: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovní režim"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Zde budou zobrazeny vaše poslední obrazovky"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"připnutí obrazovky"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmítnout"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dialog hlasitosti"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Klepnutím obnovíte originál."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Používáte pracovní profil"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Nástroj na ladění uživatelského rozhraní systému"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Zobrazovat vložené procento nabití baterie"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index aef1037..6e85d8c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Lydløs."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Arbejdstilstand"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Afvis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> er annulleret."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle de seneste applikationer er lukket."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilhotspot er slået fra."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilhotspot er slået til."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casting af din skærm er stoppet."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Arbejdstilstand er slået fra."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbejdstilstand er slået til."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbejdstilstand er slået fra."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbejdstilstand er slået til."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skærmens lysstyrke"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data er sat på pause"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> brugt"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Grænse: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbejdstilstand"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Dine seneste skærme vises her"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"bliv i app"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afvis"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er dialogboksen for lydstyrke"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tryk for at gendanne originalen."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du bruger din arbejdsprofil"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Vis procent for det indbyggede batteri"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6ba1a8e..cdc1f2a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Klingelton lautlos"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Arbeitsmodus"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> beenden"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> entfernt"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle kürzlich verwendeten Apps wurden entfernt."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Der mobile Hotspot ist deaktiviert."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Der mobile Hotspot ist aktiviert."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Die Bildschirmübertragung wurde angehalten."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Arbeitsmodus aus."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbeitsmodus an."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbeitsmodus deaktiviert."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbeitsmodus aktiviert."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helligkeit des Displays"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-/3G-Daten pausiert"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> verwendet"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> Datenlimit"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Warnung für <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeitsmodus"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Hier sehen Sie Ihre zuletzt geöffneten Apps."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Bildschirmfixierung"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ablehnen"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> regelt die Lautstärke."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Zum Wiederherstellen des Originals hier tippen"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"\", \" "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Sie verwenden Ihr Arbeitsprofil."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Eingebettete Akku-Prozentzahl anzeigen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c9c7efb..015eeae 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Ειδοποίηση ήχου στο αθόρυβο."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Λειτουργία εργασίας"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Παράβλεψη <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Απορρίφθηκαν <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Έγινε παράβλεψη όλων των πρόσφατων εφαρμογών."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Το σημείο πρόσβασης κινητής συσκευής απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Το σημείο πρόσβασης κινητής συσκευής ενεργοποιήθηκε."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Η μετάδοση της οθόνης διακόπηκε."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Η λειτουργία εργασίας είναι απενεργοποιημένη."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Η λειτουργία εργασίας είναι ενεργή."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Η λειτουργία εργασίας απενεργοποιήθηκε."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Η λειτουργία εργασίας ενεργοποιήθηκε."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Φωτεινότητα οθόνης"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Τα δεδομένα 2G-3G τέθηκαν σε παύση"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Χρησιμοποιούνται <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Όριο <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Λειτουργία εργασίας"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Οι πρόσφατες οθόνες σας εμφανίζονται εδώ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Απόρριψη"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> αποτελεί το παράθυρο διαλόγου ελέγχου έντασης"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Αγγίξτε για επαναφορά αρχικού."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Χρησιμοποιείτε το προφίλ εργασίας σας"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Εμφάνιση ποσοστού ενσωματωμένης μπαταρίας"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0d9f55e..345b3bf 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Timbre en silencio"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modo de trabajo"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rechazar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartada."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se descartaron todas las aplicaciones recientes."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Zona móvil desactivada"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona móvil activada"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmisión de pantalla detenida"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modo de trabajo desactivado"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Se desactivó el modo de trabajo."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Se activó el modo de trabajo."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Utilizados: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Las pantallas recientes aparecen aquí."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Fijar pantalla"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rechazar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> es el cuadro de diálogo de volumen."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar el original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estás usando tu perfil de trabajo"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador de IU del sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaje de la batería integrada"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a5a39ce..d29eeff 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Modo silencio"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modo de trabajo"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Se ha eliminado <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se han ignorado todas las aplicaciones recientes."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Punto de acceso móvil desactivado."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Punto de acceso móvil activado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Envío de pantalla detenido."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modo de trabajo desactivado."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabajo desactivado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabajo activado."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> utilizado"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Aquí aparecerán tus pantallas recientes"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fijación de pantalla"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rechazar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> es el cuadro de diálogo de volumen"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar la versión original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"y "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estás usando tu perfil de trabajo"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de IU del sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaje de batería insertado"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 79ab1ee..12490b1 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Vaikne kõlisti."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Töörežiim"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rakendusest <xliff:g id="APP">%s</xliff:g> loobumine."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Loobusite rakendusest <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kõikidest hiljutistest rakendustest on loobutud"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobiilside leviala on välja lülitatud."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiilside leviala on sisse lülitatud."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekraanikuva ülekandmine on peatatud."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Töörežiim on väljas."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Töörežiim on sees."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Töörežiim on välja lülitatud."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Töörežiim on sisse lülitatud."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekraani heledus"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G andmekasutus on peatatud"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> on kasutatud"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limiit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Töörežiim"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Teie viimane ekraanikuva ilmub siia"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekraanikuva kinnitamine"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Keela"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on helitugevuse dialoog"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Originaali taastamiseks puudutage."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Kasutate oma tööprofiili"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Süsteemi kasutajaliidese tuuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Kuva lisatud akutaseme protsent"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 94ce0ff..2938bd4 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Tonu-jotzailea isilik."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Lan modua"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Baztertu <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> baztertu da."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Konexioa partekatzeko aukera desaktibatu egin da."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Konexioa partekatzeko aukera aktibatu egin da."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Pantaila igortzeari utzi zaio."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Desaktibatuta dago lan modua."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Aktibatuta dago lan modua."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Desaktibatuta dago lan modua."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Aktibatuta dago lan modua."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bistaratu distira"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G datuen erabilera eten da"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> erabilita"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Muga: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Lan modua"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ikusitako azken pantailak erakusten dira hemen"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pantaila-ainguratzea"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ukatu"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> da bolumenaren leihoa"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Ukitu jatorrizkora leheneratzeko"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Work profila erabiltzen ari zara"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistemako erabiltzaile-interfazearen konfiguratzailea"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Erakutsi txertatutako bateriaren ehunekoa"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 9fbafc2..20c85ad 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"زنگ بی‌صدا."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"حالت کار"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"رد کردن <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> نادیده گرفته شد."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"همه برنامه‌های اخیر رد شدند."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"نقطه اتصال دستگاه همراه خاموش شد."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"نقطه اتصال دستگاه همراه روشن شد."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"فرستادن صفحه نمایش متوقف شد."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"حالت کار خاموش."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"حالت کار روشن."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"حالت کار خاموش شد."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"حالت کار روشن شد."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"روشنایی نمایشگر"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏داده 2G-3G موقتاً متوقف شده است"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> استفاده شده"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> محدودیت"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"حالت کار"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"صفحه‌های اخیر شما اینجا نمایان می‌شوند"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"پین کردن صفحه"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"اجازه ندارد"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> کنترل‌کننده صدا است"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"برای بازیابی کنترل‌کننده اصلی، لمس کنید."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"، "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"درحال استفاده از نمایه کاری‌تان هستید"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"تنظیم‌کننده واسط کاربری سیستم"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"نمایش درصد شارژ باتری جاسازی شده"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 6c9e9d6..e12c86e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Soittoääni: äänetön."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Työtila"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hylätään <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> hylättiin."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kaikki viimeisimmät sovellukset on hylätty."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobiiliyhteyden hotspot poistettiin käytöstä."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiiliyhteyden hotspot otettiin käyttöön."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ruudun lähetys pysäytettiin."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Työtila on poistettu käytöstä."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Työtila on käytössä."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Työtila poistettiin käytöstä."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Työtila otettiin käyttöön."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Näytön kirkkaus"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G-tiedonsiirto keskeytettiin"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"käytetty <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"kiintiö <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Työtila"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Äskettäin käytetyt ruudut näkyvät tässä"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"näytön kiinnitys"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Estä"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on äänenvoimakkuusvalinta."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Palauta alkuperäinen koskettamalla."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Käytät työprofiilia."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Näytä akun varaus kuvakkeessa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 86b207e..63cd500 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonnerie en mode silencieux"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Mode Travail"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Point d\'accès mobile désactivé."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Point d\'accès mobile activé."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Diffusion d\'écran arrêtée."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Mode Travail désactivé."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode Travail activé."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Le mode Travail est désactivé."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Le mode Travail est activé."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'écran"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G/3G désactivées"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Quantité de données utilisées :<xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vos écrans récents s\'affichent ici"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuser"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Touchez pour restaurer l\'original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Afficher le pourcentage intégré de charge"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 6953c87..04ba842 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonnerie en mode silencieux"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Mode Travail"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Point d\'accès mobile désactivé."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Point d\'accès mobile activé."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Diffusion d\'écran interrompue."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Mode Travail désactivé"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode Travail activé"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Le mode Travail est désactivé."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Le mode Travail est activé."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'affichage"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G-3G désactivées"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> utilisés"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> au maximum"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vos écrans récents s\'affichent ici"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Infos application"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuser"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Appuyez pour restaurer l\'interface d\'origine."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"&amp;quot;, &amp;quot; "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Afficher le pourcentage intégré de la batterie"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 2a2a2e0..87753d1 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Timbre silenciado"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modo de traballo"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rexeitar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Rexeitouse <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Rexeitáronse todas as aplicacións recentes."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Desactivouse a zona interactiva móbil."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Activouse a zona interactiva móbil."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Detívose a emisión en pantalla."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modo de traballo desactivado."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de traballo activado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Desactivouse o modo de traballo."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Activouse o modo de traballo."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os datos 2G-3G están en pausa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> usados"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de traballo"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"As túas pantallas recentes aparecen aquí"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información da aplicación"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixación de pantalla"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denegar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é o cadro de diálogo de volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar o orixinal."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estás usando o perfil de traballo"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Configurador da IU do sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentaxe de batería inserida"</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 6b67a20..a10f0d5 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"રિંગર શાંત છે."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"કાર્ય મોડ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખો."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> કાઢી નાખી."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"તમામ તાજેતરની એપ્લિકેશનો કાઢી નાખી."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"મોબાઇલ હોટસ્પોટ બંધ કર્યું."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"મોબાઇલ હોટસ્પોટ ચાલુ કર્યું."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"સ્ક્રીન કાસ્ટિંગ બંધ કર્યું."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"કાર્ય મોડ બંધ."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"કાર્ય મોડ ચાલુ."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"કાર્ય મોડ બંધ કર્યો."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"કાર્ય મોડ ચાલુ કર્યો."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"પ્રદર્શન તેજ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ડેટા થોભાવ્યો છે"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> વાપર્યો"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> મર્યાદા"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"કાર્ય મોડ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"તમારી તાજેતરની સ્ક્રીન્સ અહીં દેખાય છે"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"એપ્લિકેશન માહિતી"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"સ્ક્રીન પિનિંગ"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"નકારો"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> એ વૉલ્યૂમ સંવાદ છે"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"મૂળને પુનઃસ્થાપિત કરવા માટે ટચ કરો."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"તમે તમારી કાર્ય પ્રોફાઇલનો ઉપયોગ કરી રહ્યાં છો"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"સિસ્ટમ UI ટ્યૂનર"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"એમ્બેડ કરેલ બૅટરી ટકા બતાવો"</string>
diff --git a/packages/SystemUI/res/values-h560dp/config.xml b/packages/SystemUI/res/values-h560dp/config.xml
index f210d7b..8b576b9 100644
--- a/packages/SystemUI/res/values-h560dp/config.xml
+++ b/packages/SystemUI/res/values-h560dp/config.xml
@@ -18,6 +18,6 @@
 
 <resources>
     <!-- The maximum number of items to be displayed in quick settings -->
-    <integer name="quick_settings_detail_max_item_count">8</integer>
+    <integer name="quick_settings_detail_max_item_count">6</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index feba1fe..a3c8958 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"रिंगर मौन."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"कार्य मोड"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> को ख़ारिज करें."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खा़रिज कर दिया गया."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"हाल ही के सभी ऐप्लिकेशन ख़ारिज कर दिए गए."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"मोबाइल हॉटस्‍पॉट को बंद किया गया."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाइल हॉटस्‍पॉट को चालू किया गया."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्‍क्रीन कास्‍ट करना रुक गया."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"कार्य मोड बंद है."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"कार्य मोड चालू है."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"कार्य मोड बंद कर दिया गया."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"कार्य मोड चालू किया गया."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"स्क्रीन की स्क्रीन की रोशनी"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोक दिया गया है"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> उपयोग किया गया"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"आपकी हाल की स्‍क्रीन यहां दिखाई देती हैं"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रीन पिन करना"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार करें"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद है"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल वॉल्यूम को फिर से लाने के लिए स्पर्श करें."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"आप अपनी कार्य प्रोफ़ाइल का उपयोग कर रहे हैं"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"सिस्टम UI ट्यूनर"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"एम्बेड किया गया बैटरी प्रतिशत दिखाएं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index de1ca72..0e171ea 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -162,8 +162,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Softver zvona utišan."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Način rada"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacivanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> odbačena je."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Odbačene su sve nedavne aplikacije."</string>
@@ -215,14 +214,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilna žarišna točka isključena."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna žarišna točka uključena."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Emitiranje zaslona zaustavljeno."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Način rada isključen."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Način rada uključen."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Način rada isključen."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Način rada uključen."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svjetlina zaslona"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G – 3G podaci pauzirani"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
@@ -300,8 +295,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> iskorišteno"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način rada"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ovdje se pojavljuju vaši nedavni zasloni"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"prikvačivanje zaslona"</string>
@@ -416,8 +410,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> predstavlja dijaloški okvir za upravljanje glasnoćom"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da biste vratili izvorno."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Upotrebljavate radni profil"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Ugađanje korisničkog sučelja sustava"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži ugrađeni postotak baterije"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7763fa7..39336c8 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Csengő néma."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Munka mód"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"A(z) <xliff:g id="APP">%s</xliff:g> elvetése."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eltávolítva."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Az összes alkalmazás eltávolítva a nemrég használtak közül."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"A mobil hotspot kikapcsolva."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"A mobil hotspot bekapcsolva."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A képernyő átküldése leállítva."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Munka mód ki."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Munka mód be."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Munka mód kikapcsolva."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Munka mód bekapcsolva."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"A kijelző fényereje"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"A 2G és 3G adatforgalom szünetel."</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> felhasználva"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> korlát"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Munka mód"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"A legutóbbi képernyők itt jelennek meg"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"képernyő rögzítése"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Elutasítás"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás kezeli a hangerőt"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Érintse meg az eredeti érték visszaállításához."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"A munkaprofilt használja"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Kezelőfelület-hangoló"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"A beépített akkumulátor töltöttségi szintjének megjelenítése"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index cbb9a89..0d50b9c 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Զանգակը լռեցված է:"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Աշխատանքային ռեժիմ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Անտեսել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>-ը անտեսված է:"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Բոլոր վերջին հավելվածները հեռացվել են ցուցակից:"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Շարժական կապի WiFi ցրիչն անջատվեց:"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Շարժական կապի WiFi ցրիչը միացավ:"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Էկրանի հեռարձակումն ընդհատվեց:"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Աշխատանքային ռեժիմն անջատված է:"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Աշխատանքային ռեժիմը միացված է:"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Աշխատանքային ռեժիմն անջատվեց:"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Աշխատանքային ռեժիմը միացվեց:"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ցուցադրել պայծառությունը"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2Գ-3Գ տվյալների օգտագործումը դադարեցված է"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Օգտագործված է՝ <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Սահմանաչափ՝ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Աշխատանքային ռեժիմ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ձեր վերջին էկրանները տեսանելի են այստեղ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"էկրանի ամրակցում"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Մերժել"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ը ձայնի ուժգնության երկխոսության հավելված է"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Դիպչեք՝ սկզբնօրինակը վերականգնելու համար:"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Դուք օգտագործում եք ձեր աշխատանքային պրոֆիլը"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Համակարգի ՕՄ-ի կարգավորիչ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Ցուցադրել ներկառուցված մարտկոցի տոկոսայնությունը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index bbf018d..7ec4685 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Pendering senyap."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Mode kerja"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Menyingkirkan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> disingkirkan."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Hotspot seluler dinonaktifkan."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspot seluler diaktifkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmisi layar berhenti."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Mode kerja nonaktif."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mode kerja aktif."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Mode kerja dinonaktifkan."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Mode kerja diaktifkan."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan tampilan"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> digunakan"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Batas <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Peringatan <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode kerja"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Layar terkini Anda muncul di sini"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pin ke layar"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tolak"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> adalah dialog volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Sentuh untuk memulihkan aslinya."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Anda menggunakan profil kerja"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Penyetel Antarmuka Pengguna Sistem"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Tampilkan persentase baterai yang tersemat"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index f9235a0..c17e174 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Engin hringing."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Vinnustilling"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hunsa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> vísað frá."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Öll nýleg forrit fjarlægð."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Slökkt á farsímaaðgangsstað."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Kveikt á farsímaaðgangsstað."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Skjáútsendingu hætt."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Slökkt á vinnustillingu."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Kveikt á vinnustillingu."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Slökkt á vinnustillingu."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Kveikt á vinnustillingu."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Birtustig skjás"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Slökkt er á 2G- og 3G-gögnum"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> notuð"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hámark"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Vinnustilling"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Nýlegar skjámyndir birtast hér"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Forritsupplýsingar"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skjáfesting"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Hafna"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er hljóðstyrksvalmyndin"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Snertu til að færa í upprunalegt horf."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Þú ert að nota vinnusniðið"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Fínstillingar kerfisviðmóts"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Sýna innfellda rafhlöðustöðu"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index a389126..866f872 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Suoneria silenziosa."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modalità Lavoro"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Elimina <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eliminata."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tutte le applicazioni recenti sono state rimosse."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Hotspot mobile disattivato."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspot mobile attivato."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Trasmissione dello schermo interrotta."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modalità Lavoro non attiva."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modalità Lavoro attiva."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modalità Lavoro disattivata."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modalità Lavoro attivata."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosità dello schermo"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dati 2G-3G sospesi"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> utilizzati"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite di <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modalità Lavoro"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Le tue schermate recenti vengono visualizzate in questa sezione"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"blocco su schermo"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Nega"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> rappresenta la finestra di dialogo relativa al volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tocca per ripristinare l\'originale."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Stai utilizzando il profilo di lavoro"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintetizzatore interfaccia utente di sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra percentuale batteria incorporata"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index cd64034..8d3da11 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"צלצול שקט."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"מצב עבודה"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"סגור את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> נדחה."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"נקודה לשיתוף אינטרנט בנייד כבויה."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"נקודה לשיתוף אינטרנט בנייד מופעלת."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"העברת המסך הופסקה."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"מצב עבודה כבוי."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"מצב עבודה מופעל."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"מצב עבודה הושבת."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"מצב עבודה הופעל."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"בהירות תצוגה"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏השימוש בנתוני 2G-3G מושהה"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> בשימוש"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"הגבלה של <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"אזהרה - <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"מצב עבודה"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"המסכים האחרונים מופיעים כאן"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"הצמדת מסך"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"דחה"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> הוא תיבת הדו-שיח של עוצמת הקול"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"גע כדי לשחזר את עוצמת הקול המקורית."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"אתה משתמש בפרופיל העבודה שלך"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"הצג בשורת הסטטוס את אחוז עוצמת הסוללה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 39c7161..ae57a32 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"マナーモード着信。"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Work モード"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>を削除します。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>は削除されました。"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"モバイルアクセスポイントをOFFにしました。"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"モバイルアクセスポイントをONにしました。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"画面のキャストが停止しました。"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Work モードがオフです。"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Work モードがオンです。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Work モードをオフにしました。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Work モードをオンにしました。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ディスプレイの明るさ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G~3Gデータは一時停止中です"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g>使用中"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work モード"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"ここに最近の画面が表示されます"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"画面固定"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"許可しない"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>を音量ダイアログとして使用"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"タップすると元の音量ダイアログが復元されます。"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"、 "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"仕事用プロファイルを使用しています"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"システムUI調整ツール"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"内蔵電池の残量の割合を表示する"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 234891f..18d6f16 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"უხმო რეჟიმი."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"სამსახურის რეჟიმი"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-ის უგულებელყოფა."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ამოშლილია სიიდან."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ყველა ბოლო აპლიკაცია გაუქმდა."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"მობილური ქსელის წერტილი გამოირთო."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"მობილური ქსელის წერტილი ჩაირთო."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ეკრანის გადაცემა შეჩერებულია."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"სამსახურის რეჟიმი გამორთულია."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"სამსახურის რეჟიმი ჩართულია."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"სამსახურის რეჟიმი გამორთულია."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"სამსახურის რეჟიმი ჩართულია."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ეკრანის სიკაშკაშე"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G მონაცემები შეჩერებულია"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"გამოყენებულია: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ლიმიტი: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> გაფრთხილება"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"სამსახურის რეჟიმი"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"თქვენი ბოლო ეკრანები აქ გამოჩნდება"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ეკრანზე ჩამაგრება"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"უარყოფა"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ხმოვან დიალოგშია"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ორიგინალის აღდგენისათვის, შეეხეთ."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"თქვენ სამსახურის პროფილს იყენებთ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"სისტემის UI ტუნერი"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ჩამაგრებული ბატარეის პროცენტის ჩვენება"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 08e2a50..0d4b618 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Қоңырау үнсіз."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Жұмыс режимі"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> қолданбасынан бас тарту."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> алынып тасталған."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Барлық жақындағы қабылданбаған қолданбалар."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобильді хотспот өшірілді."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобильді хотспот қосылды."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Экранды трансляциялау тоқтатылды."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Жұмыс режимі өшірулі."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Жұмыс режимі қосулы."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Жұмыс режимі өшірілді."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Жұмыс режимі қосылды."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дисплей жарықтығы"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G деректері кідіртілді"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> пайдаланылған"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> шегі"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Жұмыс режимі"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Мұнда жақындағы экрандар көрсетіледі"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Қолданба туралы ақпарат"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экранды бекіту"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Өшіру"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> — көлем диалогтық терезесі"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Түпнұсқаны қалпына келтіру үшін түртіңіз."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Сіз жұмыс профиліңізді пайдаланып жатырсыз"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Жүйелік пайдаланушылық интерфейс тюнері"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Ендірілген батарея пайыздық шамасын көрсету"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 2df7f1f..8a72493 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"កម្មវិធី​រោទ៍​ស្ងាត់។"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"របៀបការងារ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"បោះបង់ <xliff:g id="APP">%s</xliff:g> ។"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"កម្មវិធីថ្មីៗទាំងអស់ត្រូវបានបោះបង់។"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"បាន​បិទ​ហតស្ប៉ត​ចល័ត។"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"បាន​បើក​ហតស្ប៉ត​ចល័ត។"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"បាន​បញ្ឈប់​ការ​ចាត់​ថ្នាក់​អេក្រង់។"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"បិទរបៀបការងារ"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"បើករបៀបការងារ"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"បានបិទរបៀបការងារ"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"បានបើករបៀបការងារ"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ពន្លឺ​ការ​បង្ហាញ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ទិន្នន័យ 2G-3G ត្រូវបានផ្អាក"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"បាន​ប្រើ <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ដែន​កំណត់ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ការ​ព្រមាន"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"របៀបការងារ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"អេក្រង់​បច្ចុប្បន្ន​របស់​អ្នក​បង្ហាញ​នៅ​ទីនេះ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ការ​ភ្ជាប់​អេក្រង់"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"បដិសេធ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> គឺជាប្រអប់សម្លេង"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ប៉ះដើម្បីស្តារច្បាប់ដើម។"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"អ្នកកំពុងប្រើប្រវត្តិរូបការងាររបស់អ្នក"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"កម្មវិធីសម្រួល UI ប្រព័ន្ធ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"បង្ហាញភាគរយថាមពលថ្មដែលបានបង្កប់"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index ee466d0..d20f0394 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"ರಿಂಗರ್ ಶಾಂತ."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"ಕೆಲಸದ ಮೋಡ್"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸು."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ಇತ್ತೀಚಿನ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"ಮೊಬೈಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ಮೊಬೈಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ಸ್ಕ್ರೀನ್ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಲಾಗಿದೆ."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಆಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ಹೊಳಪನ್ನು ಪ್ರದರ್ಶಿಸಿ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ಡೇಟಾವನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ಬಳಸಲಾಗಿದೆ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಮಿತಿ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ಕೆಲಸದ ಮೋಡ್"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"ನಿಮ್ಮ ಇತ್ತೀಚಿನ ಪರದೆಗಳು ಇಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ಸ್ಕ್ರೀನ್ ಪಿನ್ನಿಂಗ್"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ನಿರಾಕರಿಸು"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ವಾಲ್ಯೂಮ್ ಸಂವಾದವಾಗಿದೆ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ಮೂಲ ಮರುಸ್ಥಾಪಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು ನೀವು ಬಳಸುತ್ತಿರುವಿರಿ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"ಸಿಸ್ಟಮ್ UI ಟ್ಯೂನರ್"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ಎಂಬೆಡ್ ಮಾಡಲಾದ ಬ್ಯಾಟರಿ ಶೇಕಡಾ ತೋರಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 35725aa..2d61eab 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"벨소리가 무음입니다."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"작업 모드"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>을(를) 숨깁니다."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>이(가) 제거되었습니다."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"최근 사용한 애플리케이션을 모두 닫았습니다."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"모바일 핫스팟이 사용 중지되었습니다."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"모바일 핫스팟을 사용합니다."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"화면 전송이 중지되었습니다."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"작업 모드가 사용 중지되었습니다."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"작업 모드가 사용 설정되었습니다."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"작업 모드가 사용 중지되었습니다."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"작업 모드가 사용 설정되었습니다."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"디스플레이 밝기"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 데이터 사용 중지됨"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> 사용됨"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"한도: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"작업 모드"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"여기에 최근 화면이 표시됩니다."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"화면 고정"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"거부"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 볼륨 대화입니다."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"원본을 복원하려면 터치하세요."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"직장 프로필을 사용하고 있습니다."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"시스템 UI 튜너"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"내장형 배터리 잔량 비율 표시"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 79b8937..6d624d1 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Үнсүз шыңгыроо."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Иштөө режими"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> этибарга албоо."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> жок болду."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Акыркы колдонмолордун баары көз жаздымда калтырылды."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобилдик байланыш түйүнү өчүрүлдү."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилдик байланыш түйүнү күйгүзүлдү."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Тышкы экранга чыгаруу аракети токтотулду."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Иштөө режими өчүк."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Иштөө режими күйүк."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Иштөө режими өчүрүлдү."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Иштөө режими күйгүзүлдү."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Жарыктыгын көрсөтүү"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дайындары тындырылды."</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> колдонулду"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> чектөө"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Иштөө режими"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Акыркы экрандарыңыз бул жерден көрүнөт"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Колдонмо жөнүндө маалымат"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экран кадоо"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Жок"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> үндү катуулатуу диалогу"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Түпнусканы калыбына келтирүү үчүн тийип коюңуз."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Жумуш профилиңизди колдонуп жатасыз"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Батарянын кубатнын деңгээли пайыз менен көрсөтлсүн"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 015d4da..35a6e1b 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"ປິດສຽງ."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"ໂໝດການເຮັດວຽກ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ປິດ <xliff:g id="APP">%s</xliff:g> ໄວ້."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"ປິດ <xliff:g id="APP">%s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ທຸກ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ບໍ່​ດົນ​ມາ​ນີ້​ຖືກ​ປ່ອຍ​ໄປ."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"ປິດ​ຮັອດ​ສະ​ປອດ​ເຄື່ອນ​ທີ່​ແລ້ວ."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ເປີດ​ຮັອດ​ສະ​ປອດ​ເຄື່ອນ​ທີ່​ແລ້ວ."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ຢຸດ​ການ​ສົ່ງ​​ພາບ​ໜ້າ​ຈໍ​ແລ້ວ."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"ໂໝດການເຮັດວຽກປິດຢູ່."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ໂໝດການເຮັດວຽກເປີດຢູ່."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ໂໝດການເຮັດວຽກປິດຢູ່."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ໂໝດການເຮັດວຽກເປີດຢູ່."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"​ຄວາມ​ແຈ້ງ​​ຂອງ​ຈໍ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ຂໍ້​ມູນ 2G​-3G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
@@ -275,7 +270,7 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ບໍ່ມີເຄືອຂ່າຍ"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi​-Fi ປິດ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"ບໍ່​ມີ​ເຄືອ​ຂ່າຍ Wi-Fi ຢູ່"</string>
-    <string name="quick_settings_cast_title" msgid="7709016546426454729">"ຄາສທ໌"</string>
+    <string name="quick_settings_cast_title" msgid="7709016546426454729">"ການສົ່ງສັນຍານ"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"​ກຳ​ລັງ​ສົ່ງ​ສັນ​ຍານ"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"​ອຸ​ປະ​ກອນບໍ່​ມີ​ຊື່"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"​ພ້ອ​ມ​ສົ່ງ​ສັນ​ຍານ​ແລ້ວ"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"ໃຊ້​ໄປ​ແລ້ວ <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ຈຳ​ກັດ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳ​ເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ໂໝດການເຮັດວຽກ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ປະຕິເສດ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ແມ່ນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ສໍາ​ຜັດ​ເພື່ອກູ້​ຄືນ​ຕົ້ນ​ສະ​ບັບ​."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ທ່ານກຳລັງໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ສະ​ແດງ​ເປີ​ເຊັນ​ແບັດ​ເຕີ​ຣີ​ທີ່​ຕິດ​ມາ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 282866f..43d5f06 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Skambutis tylus."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Darbo režimas"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Atsisakyti <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Atsisakyta programos „<xliff:g id="APP">%s</xliff:g>“."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Atsisakyta visų naujausių programų."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobiliojo ryšio viešosios interneto prieigos taškas išjungtas."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiliojo ryšio viešosios interneto prieigos taškas įjungtas."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekrano perdavimas sustabdytas."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Darbo režimas išjungtas."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Darbo režimas įjungtas."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Darbo režimas išjungtas."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Darbo režimas įjungtas."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrano šviesumas"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G duomenys pristabdyti"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Išnaudota: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limitas: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darbo režimas"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Čia rodomi naujausi ekranai"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekrano prisegimas"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Atmesti"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ yra garsumo valdymo dialogo langas"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Palieskite, kad atkurtumėte originalą."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Naudojate darbo profilį"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistemos naudotojo sąsajos derinimo priemonė"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Rodyti įterptą akumuliat. įkrovos procentinę vertę"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 8e99c57..76bc30f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -162,8 +162,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Zvana signāls — kluss."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Darba režīms"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Nerādīt lietotni <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Lietotne <xliff:g id="APP">%s</xliff:g> vairs netiek rādīta."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Visas nesen izmantotās lietojumprogrammas tika noņemtas."</string>
@@ -215,14 +214,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilais tīklājs ir izslēgts."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilais tīklājs ir ieslēgts."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekrāna apraidīšana ir apturēta."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Darba režīms ir izslēgts."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Darba režīms ir ieslēgts."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Darba režīms ir izslēgts."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Darba režīms ir ieslēgts."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrāna spilgtums"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G datu lietojums ir apturēts"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
@@ -300,8 +295,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Tiek izmantots: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ierobežojums: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darba režīms"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Jūsu pēdējie ekrāni tiek rādīti šeit."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Piespraust ekrānu"</string>
@@ -416,8 +410,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Neatļaut"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ir skaļuma dialoglodziņš"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Pieskarieties, lai atjaunotu sākotnējo."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Jūs izmantojat darba profilu."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistēmas saskarnes regulators"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Rādīt akumulatora uzlādes līmeni procentos"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index c2de755..c4db311 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Ѕвонче на тивко."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Режим на работа"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отфрли <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> е отфрлена."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Сите неодамнешни апликации се отфрлени."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобилната точка на пристап е исклучена."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилната точка на пристап е вклучена."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Емитувањето на екранот запре."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Режимот на работа е исклучен."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Режимот на работа е вклучен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Режимот на работа е исклучен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Режимот на работа е вклучен."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветленост на екранот"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Податоците 2G-3G се паузирани"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Искористено: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Лимит: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупредување за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим на работа"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Вашите неодамнешни екрани се појавуваат тука"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информации за апликацијата"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"прикачување екран"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Одбиј"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> е дијалог за јачина на звук"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Допрете за да го вратите оригиналот."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Го користите работниот профил"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Адаптер на УИ на системот"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Прикажи вграден процент на батеријата"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 5594792..20ca46e 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"റിംഗർ നിശ്ശബ്‌ദമാണ്."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"പ്രവർത്തന മോഡ്"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> നിരസിക്കുക."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> നിരസിച്ചു."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"അടുത്തിടെയുള്ള എല്ലാ അപ്ലിക്കേഷനും നിരസിച്ചു."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"മൊബൈൽ ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കി."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"മൊബൈൽ ഹോട്ട്‌സ്‌പോട്ട് ഓണാക്കി."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"സ്ക്രീൻ കാസ്‌റ്റുചെയ്യൽ നിർത്തി."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"പ്രവർത്തന മോഡ് ഓഫാണ്."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"പ്രവർത്തന മോഡ് ഓണാണ്."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"പ്രവർത്തന മോഡ് ഓഫാക്കി."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"പ്രവർത്തന മോഡ് ഓണാക്കി."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ഡിസ്പ്ലേ തെളിച്ചം"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ഉപയോഗിച്ചു"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> പരിധി"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"പ്രവർത്തന മോഡ്"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"നിങ്ങളുടെ പുതിയ സ്ക്രീനുകൾ ഇവിടെ ദൃശ്യമാകുന്നു"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ആപ്പ് വിവരം"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"സ്ക്രീൻ പിൻ ചെയ്യൽ"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"നിരസിക്കുക"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗാണ്"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ആദ്യത്തേത് പുനഃസ്ഥാപിക്കാൻ സ്‌പർശിക്കുക."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"നിങ്ങൾ ഉപയോഗിക്കുന്നത് ഔദ്യോഗിക പ്രൊഫൈലാണ്"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"സിസ്റ്റം UI ട്യൂണർ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"എംബഡ് ചെയ്‌ത ബാറ്ററി ശതമാനം കാണിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 260a580..1a15870 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -159,8 +159,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Хонхыг хаах."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Ажлын горим"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-г хаах."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> байхгүй."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Хамгийн сүүлийн бүх програмыг арилгасан байна."</string>
@@ -212,14 +211,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобайл хотспотыг унтраасан."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобайл хотспотыг асаасан."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Дэлгэц дамжуулалт зогссон."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Ажлын горимыг унтраасан."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Ажлын горимыг асаасан."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Ажлын горимыг унтраасан."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ажлын горимыг асаасан."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дэлгэцийн гэрэлтэлт"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дата-г түр зогсоосон байна"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
@@ -297,8 +292,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ашигласан"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> хязгаар"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> анхааруулга"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ажлын горим"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Таны саяхны дэлгэц энд харагдах болно"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"дэлгэц тогтоох"</string>
@@ -413,8 +407,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Татгалзах"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог юм."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Анхны хувилбарыг эргүүлэн хадгалахыг хүсвэл хүрнэ үү."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Та өөрийн ажлын профайлыг ашиглаж байна"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Системийн UI Тохируулагч"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Залгаатай тэжээлийн хувийг харуулах"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 0c7f795..4729a04 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"रिंगर मूक."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"कार्य मोड"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> डिसमिस करा."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अनुप्रयोग डिसमिस झाले."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"मोबाईल हॉटस्पॉट बंद केला."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाईल हॉटस्पॉट चालू केला."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्क्रीन कास्ट करणे थांबले."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"कार्य मोड बंद."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"कार्य मोड चालू."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"कार्य मोड बंद केला."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"कार्य मोड चालू केला."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटास विराम दिला आहे"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> वापरले"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> मर्यादा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"आपल्या अलीकडील स्क्रीन येथे दिसतात"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग माहिती"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्‍क्रीन पिन करणे"</string>
@@ -415,13 +409,12 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"नकार द्या"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा व्हॉल्यूम संवाद आहे"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूळ पुनर्संचयित करण्यासाठी स्पर्श करा."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"आपण आपले कार्य प्रोफाईल वापरत आहात"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"सिस्टीम UI ट्यूनर"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"एम्बेडेड बॅटरी टक्केवारी दर्शवा"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"चार्ज होत नसताना स्टेटस बार चिन्हामध्‍ये बॅटरी पातळी टक्केवारी दर्शवा"</string>
-    <string name="quick_settings" msgid="10042998191725428">"दृत सेटिंग्ज"</string>
+    <string name="quick_settings" msgid="10042998191725428">"द्रुत सेटिंग्ज"</string>
     <string name="status_bar" msgid="4877645476959324760">"स्टेटस बार"</string>
     <string name="overview" msgid="4018602013895926956">"विहंगावलोकन"</string>
     <string name="demo_mode" msgid="2389163018533514619">"डेमो मोड"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 9772a3c..9a0a0c0 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Pendering senyap."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Mod kerja"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ketepikan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ditolak."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaharu diketepikan."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Tempat liputan mudah alih bergerak dimatikan."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Tempat liputan mudah alih bergerak dihidupkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Penghantaran skrin dihentikan."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Mod kerja mati."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mod kerja hidup."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Mod kerja dimatikan."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Mod kerja dihidupkan."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan paparan"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> digunakan"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> had"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mod kerja"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Skrin terbaru anda terpapar di sini"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"penyematan skrin"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tolak"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ialah dialog kelantangan"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Sentuh untuk memulihkan yang asal."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Anda sedang menggunakan profil kerja"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Penala UI Sistem"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Tunjukkan peratusan bateri terbenam"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 2b1acfb..3f1b8a7 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"ဖုန်းမြည်သံပိတ်သည်။"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"အလုပ် မုဒ်"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ကို ပယ်လိုက်ရန်"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ထုတ်ထားသည်။"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"မကြာသေးမီက အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်ပြီးပါပြီ။"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"မိုဘိုင်း ဟော့စပေါ့ ပိတ်ထား။"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"မိုဘိုင်း ဟော့စပေါ့ ဖွင့်ထား။"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"မျက်နှာပြင် ကာစ်တင် လုပ်မှု ရပ်လိုက်ပြီ။"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"အလုပ် မုဒ်ကို ပိတ်ထားပါသည်။"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"အလုပ် မုဒ်ကို ဖွင့်ထားပါသည်။"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"အလုပ် မုဒ်ကို ပိတ်ထားပါသည်။"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"အလုပ် မုဒ်ကို ဖွင့်ထားပါသည်။"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"တောက်ပမှုကို ပြရန်"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> သုံးထား"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ကန့်သတ်ချက်"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> သတိပေးချက်"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"အလုပ် မုဒ်"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"သင်၏ မကြာမီက မျက်နှာပြင်များ ဒီမှာ ပေါ်လာကြမည်"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"အပလီကေးရှင်း အင်ဖို"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"မျက်နှာပြင် ပင်ထိုးမှု"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ငြင်းပယ်သည်"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် အသံဒိုင်ယာလော့ခ်ဖြစ်သည်"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"မူရင်းအားပြန်လည်သိမ်းဆည်းရန် ထိပါ။"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"၊ "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"သင်သည် အလုပ်ပရိုဖိုင်းအား သုံးနေသည်"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"စနစ် UI ဖမ်းစက်"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"မြုတ်ထားသည့် ဘတ်ထရီ ရာခိုင်နှုန်းကို ပြပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 6dcd6bc..8bcf35e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Stille modus."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Arbeidsmodus"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Avvis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> avvist."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle nylig brukte apper er avvist."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobil Wi-Fi-sone er slått av."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil Wi-Fi-sone er slått på."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Skjermcastingen er stoppet."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Arbeidsmodusen er av."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbeidsmodusen er på."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbeidsmodusen er slått av."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbeidsmodusen er slått på."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Lysstyrken på skjermen"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- og 3G-data er satt på pause"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> brukt"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Grense på <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeidsmodus"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"De sist brukte skjermene dine vises her"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"én-appsmodus"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ikke tillat"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er volumdialogen"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Trykk for å gå tilbake til den opprinnelige volumdialogen."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"&amp;quot;, &amp;quot; "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du bruker jobbprofilen din"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Vis prosent for det innebygde batteriet"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index a05ce9b..49413b3 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"घन्टी मौन।"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"कार्य मोड"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> खारेज गर्नुहोस्।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खारेज गरिएको छ।"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"सबै हालका अनुप्रयोगहरू खारेज गरियो।"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"मोबाइल हटस्पट बन्द गरियो।"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाइल हटस्पट खुला गरियो।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्क्रिन कास्टिङ रोकियो।"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"कार्य मोड बन्द।"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"कार्य मोड अन।"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"कार्य मोड बन्द भयो।"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"कार्य मोड सक्रिय भयो।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोकिएको छ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> प्रयोग गरियो"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"तपाईँको हालको स्क्रिन यहाँ प्रकट हुन्छ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग जानकारी"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रिन पिन गर्दै"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार गर्नुहोस्"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> भोल्यूम संवाद हो"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल पुनर्स्थापना गर्न छुनुहोस्।"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"तपाईँले कार्य प्रोफाइल प्रयोग गर्दै हुनुहुन्छ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"प्रणाली UI ट्युनर"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"इम्बेड गरिएको ब्याट्री प्रतिशत देखाउनुहोस्"</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 02838bd..3a6fa0f 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"ਰਿੰਗਰ ਸਾਈਲੈਂਟ।"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"ਕੰਮ ਮੋਡ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਰੱਦ ਕਰੋ।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ਰੱਦ ਕੀਤਾ।"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ਸਾਰੀਆਂ ਹਾਲੀਆ ਐਪਲੀਕੇਸ਼ਨਾਂ ਰੱਦ ਕੀਤੀਆਂ।"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"ਮੋਬਾਈਲ ਹੌਟਸਪੌਟ ਬੰਦ ਕੀਤੀ।"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ਮੋਬਾਈਲ ਹੌਟਸਪੌਟ ਚਾਲੂ ਕੀਤੀ।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ਸਕ੍ਰੀਨ ਜੋੜਨਾ ਬੰਦ ਹੋਇਆ।"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"ਕੰਮ ਮੋਡ ਬੰਦ ਹੈ।"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"ਕੰਮ ਮੋਡ ਚਾਲੂ ਹੈ।"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ਕੰਮ ਮੋਡ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"ਕੰਮ ਮੋਡ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ਡਿਸਪਲੇ ਚਮਕ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ਡਾਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡਾਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ਵਰਤਿਆ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਸੀਮਾ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ਕੰਮ ਮੋਡ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"ਤੁਹਾਡੀਆਂ ਹਾਲੀਆ ਸਕ੍ਰੀਨਾਂ ਇੱਥੇ ਪ੍ਰਗਟ ਹੋਣਗੀਆਂ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਣਕਾਰੀ"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ਸਕ੍ਰੀਨ ਪਿਨਿੰਗ"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੋਲਯੂਮ ਡਾਇਲੌਗ ਹੈ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ਅਸਲੀ ਨੂੰ ਰੀਸਟੋਰ ਕਰਨ ਲਈ ਛੋਹਵੋ।"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ਤੁਸੀਂ ਆਪਣੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਵਰਤ ਰਹੇ ਹੋ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI ਟਿਊਨਰ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"ਜੋਡ਼ੀ ਗਈ ਬੈਟਰੀ ਪ੍ਰਤਿਸ਼ਤਤਾ ਦਿਖਾਓ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d9d1dc4..42c8f6e 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Dzwonek wyciszony."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Tryb pracy"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Usuń stąd <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>: zamknięto."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Wszystkie ostatnie aplikacje zostały zamknięte."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilny hotspot został wyłączony."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilny hotspot został włączony."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Zatrzymano przesyłanie ekranu."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Tryb pracy wyłączony."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Tryb pracy włączony."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Tryb pracy wyłączony."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Tryb pracy włączony."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jasność wyświetlacza"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Transmisja danych 2G-3G została wstrzymana"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Wykorzystano <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Tryb pracy"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Tutaj pojawią się ostatnie ekrany"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"przypinanie ekranu"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmów"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> steruje głośnością"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Dotknij, by przywrócić pierwotną."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Używasz profilu do pracy"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Kalibrator System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Pokaż procent naładowania baterii"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 7404621..e009cea 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Campainha silenciosa."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modo de trabalho"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"O ponto de acesso móvel foi desativado."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"O ponto de acesso móvel foi ativado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A transmissão de tela foi interrompida."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modo de trabalho desativado."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabalho ativado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabalho desativado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabalho ativado."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho da tela"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os dados 2G e 3G foram pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Usados: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Suas telas recentes aparecem aqui"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Negar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo referente ao volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Você está usando seu perfil de trabalho"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentagem de bateria incorporada"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e14194b..47949e0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Campainha em silêncio."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modo de trabalho"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ignorado."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todas as aplicações recentes foram ignoradas."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Zona Wi-Fi móvel desligada."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona Wi-Fi móvel ligada."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmissão do ecrã interrompida."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modo de trabalho desativado."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabalho ativado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"O modo de trabalho foi desativado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"O modo de trabalho foi ativado."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho do visor"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dados 2G-3G em pausa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> utilizado(s)"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Os ecrãs recentes aparecem aqui"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação no ecrã"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Recusar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo do volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Está a utilizar o seu perfil de trabalho"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador da interface do sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar percentagem da bateria incorporada"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 7404621..e009cea 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Campainha silenciosa."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modo de trabalho"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"O ponto de acesso móvel foi desativado."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"O ponto de acesso móvel foi ativado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A transmissão de tela foi interrompida."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modo de trabalho desativado."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabalho ativado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabalho desativado."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabalho ativado."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho da tela"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os dados 2G e 3G foram pausados"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Usados: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Suas telas recentes aparecem aqui"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Negar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo referente ao volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Você está usando seu perfil de trabalho"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizador System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostrar porcentagem de bateria incorporada"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index eacc909..03b9556 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -162,8 +162,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonerie silențioasă."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modul de lucru"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Închideți <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> a fost eliminată."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toate aplicațiile recente au fost închise."</string>
@@ -215,14 +214,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Hotspotul mobil este dezactivat."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspotul mobil este activat."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmiterea ecranului a fost oprită."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modul de lucru este dezactivat."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modul de lucru este activat."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modul de lucru a fost dezactivat."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modul de lucru a fost activat."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminozitatea ecranului"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Conexiunea de date 2G – 3G este întreruptă"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
@@ -300,8 +295,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> utilizați"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limită de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modul de lucru"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ecranele dvs. recente apar aici"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
@@ -416,8 +410,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuzați"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> afișează caseta de dialog pentru volum"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Atingeți pentru a reveni la setarea inițială."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Acum folosiți profilul de serviciu"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Afișați procentajul bateriei încorporat"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c26f785..a196ed6 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Беззвучный режим."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Рабочий режим"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Удаление приложения <xliff:g id="APP">%s</xliff:g> из списка."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Все недавние приложения закрыты."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Точка доступа отключена."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Точка доступа включена."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляция прекращена."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Рабочий режим отключен."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Рабочий режим включен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Рабочий режим отключен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Рабочий режим включен."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркость экрана"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передача данных 2G и 3G приостановлена"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Использовано: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рабочий режим"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Здесь будут показаны недавние приложения"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Заблокировать в приложении"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Нет"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> назначено регулятором громкости"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Нажмите, чтобы восстановить приложение по умолчанию."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Вы перешли в рабочий профиль"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Показывать уровень заряда батареи в процентах"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 3ef672a2..297ef78 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"හඬ නඟනය නිශ්ශබ්දයි."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"වැඩ ප්‍රකාරය"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ඉවතලන්න."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> අස් කර ඇත."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"ජංගම හොට්ස්පොටය අක්‍රිය කරන ලදි."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ජංගම හොට්ස්පොටය සක්‍රිය කරන ලදි."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"තිරය විකාශය කිරීම නැවත් වන ලදි."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිතයි."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"වැඩ ප්‍රකාරය ක්‍රියාත්මකයි."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිත කරන ලදී."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"වැඩ ප්‍රකාරය ක්‍රියාත්මක කරන ලදී."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"දීප්තිය දර්ශනය කරන්න"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G දත්ත විරාම කර ඇත"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> භාවිතා කර තිබේ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> සීමිත"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"වැඩ ප්‍රකාරය"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"මෙහි ඔබගේ මෑතක තිර පෙන්නුම් කරයි"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"යෙදුම් තොරතුරු"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"තිර ඇමිණීම"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ප්‍රතික්ෂේප කරන්න"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාරිතා සංවාදයයි"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"මුල් තත්ත්වය නැවත ප්‍රතිසාධනය කිරීමට ස්පර්ශ කරන්න."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ඔබ ඔබේ කාර්යාල පැතිකඩ භාවිත කරමින් සිටී"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"පද්ධති UI සුසරකය"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"කාවද්දන ලද බැටරි ප්‍රතිශතය පෙන්වන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2d6aa9d..8c77eaf 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Tiché zvonenie."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Pracovný režim"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zrušiť aplikáciu <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikácia <xliff:g id="APP">%s</xliff:g> bola zrušená."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všetky nedávne aplikácie boli odmietnuté."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilný hotspot je vypnutý."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilný hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Prenášanie bolo zastavené."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Pracovný režim – vyp."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Pracovný režim – zap."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Pracovný režim je vypnutý."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Pracovný režim je zapnutý."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeja"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dátové prenosy 2G a 3G sú pozastavené"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Využité: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovný režim"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vaše nedávne obrazovky sa zobrazia tu."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripnutie k obrazovke"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmietnuť"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dialóg hlasitosti"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Klepnutím obnovíte originál."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Používate svoj pracovný profil."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Tuner používateľského rozhrania systému"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Zobraziť percentá vloženej batérie"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 18fa504..9578dee 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Zvonjenje izklopljeno."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Način za delo"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Opusti aplikacijo <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je bila odstranjena."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Vse nedavne aplikacije so bile opuščene."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilna dostopna točka je izklopljena."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna dostopna točka je vklopljena."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Predvajanje zaslona je ustavljeno."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Način za delo izklopljen."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Način za delo vklopljen."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Način za delo je izklopljen."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Način za delo je vklopljen."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svetlost zaslona"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Prenos podatkov v omrežju 2G/3G je zaustavljen"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Porabljeno: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Omejitev: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način za delo"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vaši nedavni zasloni so prikazani tu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripenjanje zaslona"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Zavrni"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je pogovorno okno glede prostornine"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Dotaknite se, če želite obnoviti izvirnik."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Uporabljate delovni profil"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Uglaševalnik uporabniškega vmesnika sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži odstotek napolnjenosti vgraj. akumulatorja"</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index ab7e5b0..8b19bd8 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Zilja është heshtur."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Modaliteti i punës"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Largo <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> është hequr."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Të gjitha aplikacionet e fundit u larguan."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Qasja në zona publike interneti është e çaktivizuar."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona e qasjes publike për internet është e aktivizuar."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmetimi i ekranit ndaloi."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Modaliteti i punës është i çaktivizuar."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modaliteti i punës është i aktivizuar."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modaliteti i punës është i çaktivizuar."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modaliteti i punës është i aktivizuar."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ndriçimi i ekranit"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Të dhënat 2G-3G janë ndërprerë"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Të përdorura: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Kufiri: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modaliteti i punës"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ekranet e tua të fundit shfaqen këtu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacioni i aplikacionit"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"gozhdimi i ekranit"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuzo"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> është dialogu i volumit"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Prek për të restauruar origjinalin."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Po përdor profilin tënd të punës"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Shfaq përqindjen e baterisë së integruar"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 196d1f1..f22fa4e 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -162,8 +162,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Нечујно звоно."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Режим рада"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Одбаците <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Апликација <xliff:g id="APP">%s</xliff:g> је одбачена."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Све недавно коришћене апликације су одбачене."</string>
@@ -215,14 +214,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобилни хотспот је искључен."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилни хотспот је укључен."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Пребацивање екрана је заустављено."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Режим рада је искључен."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Режим рада је укључен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Режим рада је искључен."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Режим рада је укључен."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветљеност екрана"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G подаци су паузирани"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
@@ -300,8 +295,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Искористили сте <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничење од <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим рада"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Недавни екрани се појављују овде"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"качење екрана"</string>
@@ -416,8 +410,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Одбиј"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> је дијалог за јачину звука"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Додирните да бисте вратили оригинал."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Користите профил за Work"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Тјунер за кориснички интерфејс система"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Приказуј уграђени проценат батерије"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 31066bf..269881a 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Tyst ringsignal."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Arbetsläge"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ta bort <xliff:g id="APP">%s</xliff:g> från listan."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> togs bort permanent."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alla appar har tagits bort från listan Senaste."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Den mobila trådlösa surfzonen har inaktiverats."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Den mobila trådlösa surfzonen har aktiverats."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Castningen av skärmen har stoppats."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Arbetsläget är inaktiverat."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Arbetsläget aktiverat."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Arbetsläget har inaktiverats."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Arbetsläget har aktiverats."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skärmens ljusstyrka"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- och 3G-data har pausats"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> används"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Gräns: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbetsläge"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Dina senaste skärmar visas här"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fästa skärmen"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Neka"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> används som volymkontroll"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tryck här om du vill återställa den ursprungliga appen."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du använder din jobbprofil"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Inställningar för systemgränssnitt"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Visa inbäddad batteriprocent"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index eeeef1f..2696242 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Mlio wa simu uko kimya."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Hali ya kazi"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ondoa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> imeondolewa."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Programu za hivi majuzi zimeondolewa."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mtandao-hewa unaoweza kuhamishika umezimwa."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mtandao-hewa unaoweza kuhamishika umewashwa."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Utumaji wa skrini umesitishwa."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Hali ya kazi imezimwa."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Hali ya kazi imewashwa."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Hali ya kazi imezimwa."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Hali ya kazi imewashwa."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ung\'aavu wa skrini"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data ya 2G-3G imesitishwa"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> imetumika"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"kikomo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Hali ya kazi"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Skrini zako za hivi majuzi huonekana hapa"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kudumisha programu moja"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Kataa"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ni mazungumzo ya sauti"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Gusa ili urejeshe ya awali."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Unatumia wasifu wako wa kazini"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Kipokea Ishara cha SystemUI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Onyesha asilimia ya betri iliyopachikwa"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index a6ad0df..aa7266e 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"ரிங்கர் நிசப்தம்."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"பணிப் பயன்முறை"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ஐ நிராகரி."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> விலக்கப்பட்டது."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"எல்லா சமீபத்திய பயன்பாடுகளும் விலக்கப்பட்டன."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"மொபைல் ஹாட்ஸ்பாட் முடக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"மொபைல் ஹாட்ஸ்பாட் இயக்கப்பட்டது."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"திரையை அனுப்புதல் நிறுத்தப்பட்டது."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"பணிப் பயன்முறை முடக்கப்பட்டுள்ளது."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"பணிப் பயன்முறை இயக்கப்பட்டுள்ளது."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"பணிப் பயன்முறை முடக்கப்பட்டது."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"பணிப் பயன்முறை இயக்கப்பட்டது."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"திரை பிரகாசம்"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G டேட்டா இடைநிறுத்தப்பட்டது"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"பயன்படுத்தியது - <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> வரம்பு"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"பணிப் பயன்முறை"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"சமீபத்திய திரைகள் இங்கு தோன்றும்"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"பயன்பாட்டு தகவல்"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"திரையை பின் செய்தல்"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"நிராகரி"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"ஒலியளவு செய்தி: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"அசலை மீட்டமைக்கத் தொடவும்."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"பணி சுயவிவரத்தைப் பயன்படுத்துகிறீர்கள்"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"உள்ளிணைந்த பேட்டரி சதவீதத்தைக் காட்டு"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 468d00d..06b7ccf3 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"రింగర్ నిశ్శబ్దంలో ఉంది."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"పని మోడ్"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ని తీసివేయండి."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> తీసివేయబడింది."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"అన్ని ఇటీవలి అనువర్తనాలు తీసివేయబడ్డాయి."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"మొబైల్ హాట్‌స్పాట్ ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"మొబైల్ హాట్‌స్పాట్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"స్క్రీన్ ప్రసారం ఆపివేయబడింది."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"పని మోడ్ ఆఫ్‌లో ఉంది."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"పని మోడ్ ఆన్‌లో ఉంది."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"పని మోడ్ ఆఫ్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"పని మోడ్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ప్రదర్శన ప్రకాశం"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G డేటా పాజ్ చేయబడింది"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> వినియోగించబడింది"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> పరిమితి"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"పని మోడ్"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"మీ ఇటీవలి స్క్రీన్‌లు ఇక్కడ కనిపిస్తాయి"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"అనువర్తన సమాచారం"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"స్క్రీన్ పిన్నింగ్"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"తిరస్కరించు"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> అనేది వాల్యూమ్ డైలాగ్"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"అసలుదాన్ని పునరుద్ధరించడానికి తాకండి."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"మీరు మీ కార్యాలయ ప్రొఫైల్‌ను ఉపయోగిస్తున్నారు"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"సిస్టమ్ UI ట్యూనర్"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"పొందుపరిచిన బ్యాటరీ శాతం చూపు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 130a8bf..eb4eb27 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"เสียงเรียกเข้าแบบปิดเสียง"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"โหมดการทำงาน"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ยกเลิก <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ถูกลบไปแล้ว"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ปิดแอปพลิเคชันล่าสุดทั้งหมดแล้ว"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"ปิดฮอตสปอตเคลื่อนที่แล้ว"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"เปิดฮอตสปอตเคลื่อนที่แล้ว"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"หยุดการส่งหน้าจอแล้ว"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"โหมดการทำงานปิดอยู่"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"โหมดการทำงานเปิดอยู่"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"ปิดโหมดการทำงานแล้ว"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"เปิดโหมดการทำงานแล้ว"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ความสว่างของหน้าจอ"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"หยุดการใช้ข้อมูล 2G-3G ชั่วคราวแล้ว"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"ใช้ไปแล้ว <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ขีดจำกัด <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"คำเตือน <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"โหมดการทำงาน"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"หน้าจอล่าสุดของคุณแสดงที่นี่"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"การตรึงหน้าจอ"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ปฏิเสธ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> เป็นช่องโต้ตอบระดับเสียง"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"แตะเพื่อคืนค่าดั้งเดิม"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"คุณกำลังใช้โปรไฟล์งานของคุณ"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"ตัวรับสัญญาณ UI ระบบ"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"แสดงเปอร์เซ็นต์ของแบตเตอรี่ในตัว"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 2546c9e..a04d66b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Naka-silent ang ringer."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Work mode"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"I-dismiss ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Hindi pinansin ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Na-dismiss ang lahat ng kamakailang application."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Na-off ang mobile hotspot."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Na-on ang mobile hotspot."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Itinigil ang pagka-cast sa screen."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Naka-off ang work mode."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Naka-on ang work mode."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Na-off ang work mode."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Na-on ang work mode."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Liwanag ng display"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Naka-pause ang 2G-3G data"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ang nagamit"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ang limitasyon"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Babala sa <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Lumalabas dito ang iyong mga kamakailang screen"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pagpi-pin sa screen"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tanggihan"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ang volume dialog"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Pindutin upang ibalik ang orihinal."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Ginagamit mo ang iyong profile sa trabaho"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Tuner ng System UI"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Ipakita ang naka-embed na porsyento ng baterya"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c9aa1f5..c549798 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Telefon zili sessiz."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Çalışma modu"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> uygulamasını kapat."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> kaldırıldı."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tüm son uygulamalar kapatıldı."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobil hotspot kapatıldı."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil hotspot açıldı."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekran yayını durduruldu."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Çalışma modu kapalı."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Çalışma modu açık."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Çalışma modu kapatıldı."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Çalışma modu açıldı."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran parlaklığı"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G veri kullanımı duraklatıldı"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> kullanıldı"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Sınır: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Çalışma modu"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Son ekranlarınız burada görünür"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sabitleme"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Reddet"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olarak ayarlandı"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Orijinali geri yüklemek için dokunun."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"İş profilinizi kullanıyorsunuz"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Sistem Arayüzü Ayarlayıcısı"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Yerleşik pil yüzdesini göster"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 58ae655..a58c13c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -163,8 +163,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Дзвінок беззвучний."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Робочий режим"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Видалити додаток <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Програму <xliff:g id="APP">%s</xliff:g> закрито."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усі останні додатки закрито."</string>
@@ -216,14 +215,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобільну точку доступу вимкнено."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобільну точку доступу ввімкнено."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляцію екрана зупинено."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Робочий режим вимкнено."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Робочий режим увімкнено."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Робочий режим вимкнено."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Робочий режим увімкнено."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яскравість дисплея"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передавання даних 2G–3G призупинено"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
@@ -301,8 +296,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Використовується: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Обмеження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Робочий режим"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ваші останні екрани відображаються тут"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"закріпити екран"</string>
@@ -417,8 +411,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Відхилити"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> призначено регулятором гучності"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Торкніться, щоб відновити оригінал."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Ви в робочому профілі"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Показувати заряд акумулятора у відсотках"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 9d42aad..9e3a6b5 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"رنگر خاموش۔"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"کام موڈ"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> کو مسترد کریں۔"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> کو ہٹا دیا گیا۔"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"سبھی حالیہ ایپلیکیشنز کو برخاست کر دیا گیا۔"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"موبائل ہاٹ اسپاٹ کو آف کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"موبائل ہاٹ اسپاٹ کو آن کر دیا گیا۔"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"اسکرین کو کاسٹ کرنا بند کر دیا۔"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"کام موڈ آف ہے۔"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"کام موڈ آن ہے۔"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"کام موڈ آف ہو گیا۔"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"کام موڈ آن ہو گیا۔"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ڈسپلے کی چمک"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏2G-3G ڈیٹا موقوف کر دیا گیا"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> استعمال کردہ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> حد"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"کام موڈ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"آپ کی حالیہ اسکرینز یہاں ظاہر ہوتی ہیں"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ایپلیکیشن کی معلومات"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"اسکرین کو پن کرنا"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"مسترد کریں"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ ہے"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"اصل کو بحال کرنے کیلئے ٹچ کریں۔"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"، "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"آپ اپنا دفتری پروفائل استعمال کر رہے ہیں۔"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"‏سسٹم UI ٹیونر"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"سرایت کردہ بیٹری کی فیصد دکھائیں"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index f7959ea..d011169 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Ovozsiz qo‘ng‘iroq."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Ish rejimi"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Olib tashlash: <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> olib tashlangan."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Yaqinda ishlatilgan barcha ilovalar olib tashlandi."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobil ulanish nuqtasi o‘chirildi."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil ulanish nuqtasi yoqildi."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekranni translatsiya qilish to‘xtadi."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Ish rejimi o‘chiq."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Ish rejimi yoniq."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Ish rejimi o‘chirib qo‘yildi."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Ish rejimi yoqildi."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran yorqinligi"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G internet to‘xtatib qo‘yildi"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> foydalanilgan"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Cheklov: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ish rejimi"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Siz yaqinda ishlatgan ilova ekranlari bu yerda ko‘rinadi"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"o‘zgarmas ekran"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rad etish"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ovoz balandligini boshqaradi"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Aslini tiklash uchun bosing."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Siz ishchi profildan foydalanmoqdasiz"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"SystemUI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Batareya foizi ko‘rsatilsin"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ffcc73a..81b5129 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Chuông im lặng."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Chế độ làm việc"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Xóa bỏ <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> đã bị loại bỏ."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Đã tắt điểm phát sóng di động."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Đã bật điểm phát sóng di động."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Đã ngừng truyền màn hình."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Chế độ làm việc tắt."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Chế độ làm việc bật."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Chế độ làm việc đã tắt."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Chế độ làm việc đã bật."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Độ sáng màn hình"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Đã tạm dừng dữ liệu 2G-3G"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Đã sử dụng <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Giới hạn <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Chế độ làm việc"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Màn hình gần đây của bạn sẽ xuất hiện tại đây"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"khóa màn hình"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Từ chối"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> là hộp thoại khối lượng"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Chạm để khôi phục bản gốc."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Bạn đang sử dụng hồ sơ công việc của mình"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Bộ điều hướng giao diện người dùng hệ thống"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Hiển thị tỷ lệ phần trăm pin được nhúng"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2d8dd2a..e06052e 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"振铃器静音。"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"工作模式"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"移除<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"已删除<xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"已关闭所有最近用过的应用。"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"移动热点已关闭。"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"移动热点已开启。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"屏幕投射已停止。"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"工作模式关闭。"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"工作模式开启。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"工作模式已关闭。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"工作模式已开启。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"屏幕亮度"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 数据网络已暂停使用"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"已使用<xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限为<xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"您最近浏览过的屏幕会显示在此处"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"固定屏幕"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒绝"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已用作音量控制对话框"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"触摸即可恢复原始设置。"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"、 "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您当前正在使用工作资料"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"系统界面调谐器"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"嵌入式显示电池电量百分比 显示嵌入的电池电量百分比"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 569d847..37d3ca6 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"鈴聲靜音。"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"工作模式"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"流動熱點已關閉。"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"流動熱點已開啟。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"已停止投放螢幕。"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"工作模式已關閉。"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"工作模式已開啟。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"已關閉工作模式。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"已開啟工作模式。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"顯示光暗度"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"已使用 <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"您最近的螢幕顯示在這裡"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話框"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸即可復原。"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"、 "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用工作設定檔"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"系統使用者介面調諧器"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"顯示嵌入的電池百分比"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f2ffe16..531b3cd 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"鈴聲靜音。"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"工作模式"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"可攜式無線基地台已關閉。"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"可攜式無線基地台已開啟。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"已停止投放螢幕。"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"工作模式已關閉。"</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"工作模式已開啟。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"工作模式已關閉。"</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"工作模式已開啟。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"螢幕亮度"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據連線"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"已使用 <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"您最近的螢幕會顯示在這裡"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在是預設的音量控制對話方塊。"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸這裡即可恢復原始設定。"</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">"、 "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用 Work 設定檔"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"系統使用者介面調整精靈"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"顯示嵌入式電池百分比"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index efa04e6..b8e6a0f 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -161,8 +161,7 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Isikhali sithulile."</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <!-- no translation found for accessibility_work_mode (2478631941714607225) -->
-    <skip />
+    <string name="accessibility_work_mode" msgid="2478631941714607225">"Imodi yomsebenzi"</string>
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Cashisa i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ivaliwe."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Zonke izinhlelo zokusebenza zakamuva zicashisiwe."</string>
@@ -214,14 +213,10 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"I-hotspot ivaliwe."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"I-hotspot ivuliwe."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ukusakaza kwesikrini kumisiwe."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (7045417396436552890) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_on (7650588553988014341) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (5605534876107300711) -->
-    <skip />
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_on (249840330756998612) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Imodi yomsebenzi ivaliwe."</string>
+    <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Imodi yomsebenzi ivuliwe."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Imodi yomsebenzi ivaliwe."</string>
+    <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Imodi yomsebenzi ivuliwe."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bonisa ukukhanya"</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G idatha imisiwe"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
@@ -299,8 +294,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> isetshenzisiwe"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> umkhawulo"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
-    <!-- no translation found for quick_settings_work_mode_label (6244915274350490429) -->
-    <skip />
+    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Imodi yomsebenzi"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Izikrini zakho zakamuva zivela lapha"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ukuphina isikrini"</string>
@@ -415,8 +409,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Phika"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> yingxoxo yevolumu"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Thinta ukuze ubuyisele kokwangempela."</string>
-    <!-- no translation found for group_summary_concadenation (6846402378100148789) -->
-    <skip />
+    <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Usebenzisa iphrofayela yakho yomsebenzi"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Isishuni se-UI yesistimu"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Bonisa amaphesenti ebhethri elinamathiselwe"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5618e9b..94350d9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -68,6 +68,8 @@
     <color name="recents_task_view_lock_to_app_button_background_color">#ffe6e6e6</color>
     <!-- The lock to task button foreground color. -->
     <color name="recents_task_view_lock_to_app_button_color">#ff666666</color>
+    <!-- The background color for the freeform workspace. -->
+    <color name="recents_freeform_workspace_bg_color">#66000000</color>
 
     <color name="keyguard_affordance">#ffffffff</color>
 
@@ -100,9 +102,9 @@
     <color name="current_user_border_color">@color/system_accent_color</color>
 
     <!-- The "inside" of a notification, reached via longpress -->
-    <color name="notification_guts_bg_color">@color/system_secondary_color</color>
-    <color name="notification_guts_title_color">#FFFFFFFF</color>
-    <color name="notification_guts_text_color">#b2FFFFFF</color>
+    <color name="notification_guts_bg_color">@*android:color/material_deep_teal_500</color>
+    <color name="notification_guts_title_color">#B2DFDB</color>
+    <color name="notification_guts_text_color">#FFFFFFFF</color>
     <color name="notification_guts_btn_color">#FFFFFFFF</color>
 
     <color name="assist_orb_color">#ffffff</color>
@@ -144,4 +146,7 @@
 
     <color name="docked_divider_background">#ff000000</color>
     <color name="docked_divider_handle">#ffffff</color>
+
+    <color name="default_remote_input_background">@*android:color/notification_default_color</color>
+    <color name="remote_input_hint">#4dffffff</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a0052ce..40e8b50 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,7 +103,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
+        wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast
     </string>
 
     <!-- The tiles to display in QuickSettings -->
@@ -117,7 +117,7 @@
     <integer name="quick_settings_brightness_dialog_long_timeout">4000</integer>
 
     <!-- The maximum number of items to be displayed in quick settings -->
-    <integer name="quick_settings_detail_max_item_count">7</integer>
+    <integer name="quick_settings_detail_max_item_count">5</integer>
 
     <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
     <bool name="config_show4GForLTE">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 65b0c45..4f070d6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -45,8 +45,11 @@
     <!-- Height of a large notification in the status bar -->
     <dimen name="notification_max_height">276dp</dimen>
 
-    <!-- Height of a medium notification in the status bar -->
-    <dimen name="notification_mid_height">128dp</dimen>
+    <!-- Height of a heads up notification in the status bar for legacy custom views -->
+    <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
+
+    <!-- Height of a heads up notification in the status bar -->
+    <dimen name="notification_max_heads_up_height">140dp</dimen>
 
     <!-- Height of a the summary ("more card") notification on keyguard. -->
     <dimen name="notification_summary_height">44dp</dimen>
@@ -95,7 +98,7 @@
     <dimen name="close_handle_underlap">32dp</dimen>
 
     <!-- Height of the status bar header bar -->
-    <dimen name="status_bar_header_height">60dp</dimen>
+    <dimen name="status_bar_header_height">90dp</dimen>
 
     <!-- Height of the status bar header bar when expanded -->
     <dimen name="status_bar_header_height_expanded">116dp</dimen>
@@ -133,6 +136,7 @@
     <dimen name="qs_quick_actions_padding">25dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
+    <dimen name="qs_date_anim_translation">44.5dp</dimen>
     <dimen name="qs_page_indicator_size">12dp</dimen>
     <dimen name="qs_tile_icon_size">24dp</dimen>
     <dimen name="qs_tile_text_size">12sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 666a024..9b74a80 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -713,8 +713,8 @@
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
     <string name="recents_show_history_button_label">More</string>
-    <!-- Recents: The history of recents. [CHAR LIMIT=NONE] -->
-    <string name="recents_history_label">History</string>
+    <!-- Recents: A format string to set the number of availabe historical tasks in recents. [CHAR LIMIT=NONE] -->
+    <string name="recents_history_label_format"><xliff:g id="number">%d</xliff:g> More</string>
 
     <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 8dcf8a7..e31927e 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -18,25 +18,10 @@
     xmlns:sysui="http://schemas.android.com/apk/res-auto"
     android:title="@string/system_ui_tuner">
 
-    <PreferenceScreen
-        android:title="@string/quick_settings">
-
-        <PreferenceCategory
-            android:title="@string/experimental">
-
-            <com.android.systemui.tuner.TunerSwitch
-                android:key="qs_show_brightness"
-                android:title="@string/show_brightness"
-                sysui:defValue="true" />
-
-            <com.android.systemui.tuner.QSPagingSwitch
-                android:key="qs_paged_panel"
-                android:title="@string/qs_paging" />
-
-        </PreferenceCategory>
-
-    </PreferenceScreen>
-
+    <com.android.systemui.tuner.TunerSwitch
+        android:key="qs_show_brightness"
+        android:title="@string/show_brightness"
+        sysui:defValue="true" />
 
     <PreferenceScreen
         android:title="@string/status_bar" >
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6207324..870e0af 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -246,7 +246,10 @@
                             mWatchLongPress = new Runnable() {
                                 @Override
                                 public void run() {
-                                    if (mCurrView != null && !mLongPressSent) {
+                                    float pos = getPos(ev);
+                                    float delta = pos - mInitialTouchPos;
+                                    if (mCurrView != null && !mLongPressSent
+                                            && Math.abs(delta) < mPagingTouchSlop) {
                                         mLongPressSent = true;
                                         mCurrView.sendAccessibilityEvent(
                                                 AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index 5b8d3d6..c9ba885 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.content.Context;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
@@ -35,13 +36,19 @@
 
     private final Paint mDarkPaint = new Paint();
     private final Interpolator mLinearOutSlowInInterpolator;
-    private final ArrayList<View> mTargets;
     private final ColorMatrix mMatrix = new ColorMatrix();
     private final ColorMatrix mGrayscaleMatrix = new ColorMatrix();
     private final long mFadeDuration;
+    private final ArrayList<View> mTargets = new ArrayList<>();
 
-    public ViewInvertHelper(View target, long fadeDuration) {
-        this(constructArray(target), fadeDuration);
+    public ViewInvertHelper(View v, long fadeDuration) {
+        this(v.getContext(), fadeDuration);
+        addTarget(v);
+    }
+    public ViewInvertHelper(Context context, long fadeDuration) {
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                android.R.interpolator.linear_out_slow_in);
+        mFadeDuration = fadeDuration;
     }
 
     private static ArrayList<View> constructArray(View target) {
@@ -50,11 +57,12 @@
         return views;
     }
 
-    public ViewInvertHelper(ArrayList<View> targets, long fadeDuration) {
-        mTargets = targets;
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(mTargets.get(0).getContext(),
-                android.R.interpolator.linear_out_slow_in);
-        mFadeDuration = fadeDuration;
+    public void clearTargets() {
+        mTargets.clear();
+    }
+
+    public void addTarget(View target) {
+        mTargets.add(target);
     }
 
     public void fade(final boolean invert, long delay) {
@@ -112,4 +120,12 @@
         mMatrix.preConcat(mGrayscaleMatrix);
         mDarkPaint.setColorFilter(new ColorMatrixColorFilter(mMatrix));
     }
+
+    public void setInverted(boolean invert, boolean fade, long delay) {
+        if (fade) {
+            fade(invert, delay);
+        } else {
+            update(invert);
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
index cb6708e..699273a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -98,7 +98,7 @@
             }
         }
 
-        setMeasuredDimension(width, getDefaultSize(totalHeight, heightMeasureSpec));
+        setMeasuredDimension(width, resolveSizeAndState(totalHeight, heightMeasureSpec, 0));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5d3fbe2..16fd9eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -19,14 +19,12 @@
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -36,7 +34,6 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
@@ -56,7 +53,6 @@
 public class QSPanel extends FrameLayout implements Tunable {
 
     public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
-    public static final String QS_THE_NEW_QS = "qs_paged_panel";
 
     protected final Context mContext;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
@@ -102,20 +98,25 @@
         updateDetailText();
         mDetail.setVisibility(GONE);
         mDetail.setClickable(true);
-        mBrightnessView = LayoutInflater.from(context).inflate(
-                R.layout.quick_settings_brightness_dialog, this, false);
-        mFooter = new QSFooter(this, context);
         addView(mDetail);
 
         mQsContainer = new LinearLayout(mContext);
         mQsContainer.setOrientation(LinearLayout.VERTICAL);
         mQsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
                 LayoutParams.WRAP_CONTENT));
-
         addView(mQsContainer);
 
+        mBrightnessView = LayoutInflater.from(context).inflate(
+                R.layout.quick_settings_brightness_dialog, this, false);
         mQsContainer.addView(mBrightnessView);
+
+        mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
+                R.layout.qs_paged_tile_layout, mQsContainer, false);
+        mQsContainer.addView((View) mTileLayout);
+
+        mFooter = new QSFooter(this, context);
         mQsContainer.addView(mFooter.getView());
+
         mClipper = new QSDetailClipper(mDetail);
         updateResources();
 
@@ -136,7 +137,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS, QS_THE_NEW_QS);
+        TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS);
     }
 
     @Override
@@ -150,34 +151,27 @@
         if (QS_SHOW_BRIGHTNESS.equals(key)) {
             mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
                     ? VISIBLE : GONE);
-        } else if (QS_THE_NEW_QS.equals(key)) {
-            boolean theNewQs = newValue != null && Integer.parseInt(newValue) != 0;
-            if (mTileLayout != null) {
-                for (int i = 0; i < mRecords.size(); i++) {
-                    mTileLayout.removeTile(mRecords.get(i));
-                }
-                mQsContainer.removeView((View) mTileLayout);
-            }
-            int layout = theNewQs
-                    ? R.layout.qs_paged_tile_layout : R.layout.qs_tile_layout;
-            mTileLayout =
-                    (QSTileLayout) LayoutInflater.from(mContext).inflate(layout, mQsContainer, false);
-            mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
-            for (int i = 0; i < mRecords.size(); i++) {
-                mTileLayout.addTile(mRecords.get(i));
-            }
-            if (theNewQs) {
-                mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext)
-                        .inflate(R.layout.qs_customize_panel, null);
-                mCustomizePanel.setHost(mHost);
-            } else {
-                if (mCustomizePanel != null && mCustomizePanel.isCustomizing()) {
-                    mCustomizePanel.hide(mCustomizePanel.getWidth() / 2,
-                            mCustomizePanel.getHeight() / 2);
-                }
-                mCustomizePanel = null;
+        }
+    }
+
+    public void openDetails(String subPanel) {
+        QSTile<?> tile = getTile(subPanel);
+        showDetailAdapter(true, tile.getDetailAdapter(), new int[] {getWidth() / 2, 0});
+    }
+
+    private QSTile<?> getTile(String subPanel) {
+        for (int i = 0; i < mRecords.size(); i++) {
+            if (subPanel.equals(mRecords.get(i).tile.getTileSpec())) {
+                return mRecords.get(i).tile;
             }
         }
+        return mHost.createTile(subPanel);
+    }
+
+    protected void createCustomizePanel() {
+        mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext)
+                .inflate(R.layout.qs_customize_panel, null);
+        mCustomizePanel.setHost(mHost);
     }
 
     private void updateDetailText() {
@@ -200,6 +194,7 @@
     public void setHost(QSTileHost host) {
         mHost = host;
         mFooter.setHost(host);
+        createCustomizePanel();
     }
 
     public QSTileHost getHost() {
@@ -608,9 +603,4 @@
         int getOffsetTop(TileRecord tile);
         void updateResources();
     }
-
-    public static boolean isTheNewQS(Context context) {
-        return Settings.Secure.getIntForUser(context.getContentResolver(), QS_THE_NEW_QS,
-                ActivityManager.getCurrentUser(), 0) != 0;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index fe8ce9b..bda4675 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -128,9 +128,10 @@
         }
 
         private LayoutParams generateLayoutParams() {
-            int size =
-                    mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
-            LayoutParams lp = new LayoutParams(size, size);
+            int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+            LayoutParams lp = new LayoutParams(0, size);
+            lp.weight = 1;
+            lp.gravity = Gravity.CENTER;
             return lp;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index 8dda9ba..87c2973 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -81,6 +81,11 @@
         }
     }
 
+    @Override
+    protected void createCustomizePanel() {
+        // Already in CustomizePanel.
+    }
+
     public void tileSelected(QSTile<?> tile, ClipData currentClip) {
         String sourceSpec = getSpec(currentClip);
         String destSpec = tile.getTileSpec();
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 baad370..4a7d67f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -37,9 +37,7 @@
 import android.widget.ListView;
 import android.widget.Toolbar;
 import android.widget.Toolbar.OnMenuItemClickListener;
-
 import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.customize.DropButton.OnDropListener;
@@ -80,14 +78,13 @@
 
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
-        mPhoneStatusBar = ((SystemUIApplication) mContext.getApplicationContext())
-                .getComponent(PhoneStatusBar.class);
         mClipper = new QSDetailClipper(this);
     }
 
     public void setHost(QSTileHost host) {
         mHost = host;
         mHost.addCallback(this);
+        mPhoneStatusBar = host.getPhoneStatusBar();
         mQsPanel.setTiles(mHost.getTiles());
         mQsPanel.setHost(mHost);
         mQsPanel.setSavedTiles();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 5fb76c8..6c7b337 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -86,6 +86,14 @@
     }
 
     @Override
+    protected void handleSecondaryClick() {
+        boolean dataEnabled = mDataController.isMobileDataSupported()
+                && mDataController.isMobileDataEnabled();
+        MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, !dataEnabled);
+        mDataController.setMobileDataEnabled(!dataEnabled);
+    }
+
+    @Override
     protected void handleUpdateState(SignalState state, Object arg) {
         CallbackInfo cb = (CallbackInfo) arg;
         if (cb == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 384b86f..1bc9a63 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -87,6 +87,9 @@
     private final static String TAG = "RecentsActivity";
     private final static boolean DEBUG = false;
 
+    private final static String KEY_SAVED_STATE_HISTORY_VISIBLE =
+            "saved_instance_state_history_visible";
+
     public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
 
     private RecentsPackageMonitor mPackageMonitor;
@@ -97,8 +100,6 @@
     // Top level views
     private RecentsView mRecentsView;
     private SystemBarScrimViews mScrimViews;
-    private ViewStub mEmptyViewStub;
-    private View mEmptyView;
     private ViewStub mHistoryViewStub;
     private RecentsHistoryView mHistoryView;
 
@@ -197,7 +198,6 @@
         loader.loadTasks(this, plan, loadOpts);
 
         TaskStack stack = plan.getTaskStack();
-        launchState.launchedWithNoRecentTasks = !plan.hasTasks();
         mRecentsView.setTaskStack(stack);
 
         // Mark the task that is the launch target
@@ -215,30 +215,13 @@
             }
         }
 
-        // Update the top level view's visibilities
-        if (launchState.launchedWithNoRecentTasks) {
-            if (mEmptyView == null) {
-                mEmptyView = mEmptyViewStub.inflate();
-            }
-            mEmptyView.setVisibility(View.VISIBLE);
-            if (!RecentsDebugFlags.Static.DisableSearchBar) {
-                mRecentsView.setSearchBarVisibility(View.GONE);
-            }
-        } else {
-            if (mEmptyView != null) {
-                mEmptyView.setVisibility(View.GONE);
-            }
-            if (!RecentsDebugFlags.Static.DisableSearchBar) {
-                if (mRecentsView.hasValidSearchBar()) {
-                    mRecentsView.setSearchBarVisibility(View.VISIBLE);
-                } else {
-                    refreshSearchWidgetView();
-                }
-            }
-        }
-
         // Animate the SystemUI scrims into view
-        mScrimViews.prepareEnterRecentsAnimation();
+        boolean hasStatusBarScrim = stack.getStackTaskCount() > 0;
+        boolean animateStatusBarScrim = launchState.launchedFromHome;
+        boolean hasNavBarScrim = (stack.getStackTaskCount() > 0) && !config.hasTransposedNavBar;
+        boolean animateNavBarScrim = true;
+        mScrimViews.prepareEnterRecentsAnimation(hasStatusBarScrim, animateStatusBarScrim, hasNavBarScrim,
+                animateNavBarScrim);
 
         // Keep track of whether we launched from the nav bar button or via alt-tab
         if (launchState.launchedWithAltTab) {
@@ -265,7 +248,10 @@
     boolean dismissHistory() {
         // Try and hide the history view first
         if (mHistoryView != null && mHistoryView.isVisible()) {
-            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
+            ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
+            t.increment();
+            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */, t));
+            t.decrement();
             return true;
         }
         return false;
@@ -374,7 +360,6 @@
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-        mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
         mHistoryViewStub = (ViewStub) findViewById(R.id.history_view_stub);
         mScrimViews = new SystemBarScrimViews(this);
         getWindow().getAttributes().privateFlags |=
@@ -456,7 +441,10 @@
         // Reset some states
         mIgnoreAltTabRelease = false;
         if (mHistoryView != null) {
-            EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
+            ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
+            t.increment();
+            EventBus.getDefault().send(new HideHistoryEvent(false /* animate */, t));
+            t.decrement();
         }
 
         // Notify that recents is now hidden
@@ -515,6 +503,25 @@
     }
 
     @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE,
+                (mHistoryView != null) && mHistoryView.isVisible());
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        if (savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
+            ReferenceCountedTrigger postHideStackAnimationTrigger =
+                    new ReferenceCountedTrigger(this);
+            postHideStackAnimationTrigger.increment();
+            EventBus.getDefault().send(new ShowHistoryEvent(postHideStackAnimationTrigger));
+            postHideStackAnimationTrigger.decrement();
+        }
+    }
+
+    @Override
     public void onTrimMemory(int level) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
         if (loader != null) {
@@ -603,16 +610,18 @@
     }
 
     public final void onBusEvent(IterateRecentsEvent event) {
-        // Focus the next task
-        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+        if (!dismissHistory()) {
+            // Focus the next task
+            EventBus.getDefault().send(new FocusNextTaskViewEvent());
 
-        // Start dozing after the recents button is clicked
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
-        if (debugFlags.isFastToggleRecentsEnabled()) {
-            if (!mIterateTrigger.isDozing()) {
-                mIterateTrigger.startDozing();
-            } else {
-                mIterateTrigger.poke();
+            // Start dozing after the recents button is clicked
+            RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+            if (debugFlags.isFastToggleRecentsEnabled()) {
+                if (!mIterateTrigger.isDozing()) {
+                    mIterateTrigger.startDozing();
+                } else {
+                    mIterateTrigger.poke();
+                }
             }
         }
     }
@@ -630,7 +639,7 @@
         } else if (event.triggeredFromHomeKey) {
             // Otherwise, dismiss Recents to Home
             if (mHistoryView != null && mHistoryView.isVisible()) {
-                ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
+                ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
                 t.increment();
                 t.addLastDecrementRunnable(new Runnable() {
                     @Override
@@ -651,7 +660,7 @@
 
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
         // Try and start the enter animation (or restart it on configuration changed)
-        ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
+        ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
         ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
         ctx.postAnimationTrigger.increment();
         if (mSearchWidgetInfo != null) {
@@ -724,8 +733,13 @@
     }
 
     public final void onBusEvent(AllTaskViewsDismissedEvent event) {
-        // Just go straight home (no animation necessary because there are no more task views)
-        dismissRecentsToHome(false /* animated */);
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.hasDockedTask()) {
+            mRecentsView.showEmptyView();
+        } else {
+            // Just go straight home (no animation necessary because there are no more task views)
+            dismissRecentsToHome(false /* animated */);
+        }
 
         // Keep track of all-deletions
         MetricsLogger.count(this, "overview_task_all_dismissed", 1);
@@ -769,13 +783,11 @@
             // provided.
             mHistoryView.setSystemInsets(mRecentsView.getSystemInsets());
         }
-        mHistoryView.show(mRecentsView.getTaskStack());
+        mHistoryView.show(mRecentsView.getTaskStack(), event.postHideStackAnimationTrigger);
     }
 
     public final void onBusEvent(HideHistoryEvent event) {
-        if (mHistoryView != null) {
-            mHistoryView.hide(event.animate, event.postAnimationTrigger);
-        }
+        mHistoryView.hide(event.animate, event.postHideHistoryAnimationTrigger);
     }
 
     private void refreshSearchWidgetView() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index e0bd59b..03b3788 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -28,7 +28,6 @@
 public class RecentsActivityLaunchState {
 
     public boolean launchedWithAltTab;
-    public boolean launchedWithNoRecentTasks;
     public boolean launchedFromAppWithThumbnail;
     public boolean launchedFromHome;
     public boolean launchedFromSearchHome;
@@ -49,28 +48,6 @@
         launchedViaDragGesture = false;
     }
 
-    /** Returns whether the status bar scrim should be animated when shown for the first time. */
-    public boolean shouldAnimateStatusBarScrim() {
-        return true;
-    }
-
-    /** Returns whether the status bar scrim should be visible. */
-    public boolean hasStatusBarScrim() {
-        return !launchedWithNoRecentTasks;
-    }
-
-    /** Returns whether the nav bar scrim should be animated when shown for the first time. */
-    public boolean shouldAnimateNavBarScrim() {
-        return true;
-    }
-
-    /** Returns whether the nav bar scrim should be visible. */
-    public boolean hasNavBarScrim() {
-        // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
-        RecentsConfiguration config = Recents.getConfiguration();
-        return !launchedWithNoRecentTasks && !config.hasTransposedNavBar;
-    }
-
     /**
      * Returns the task to focus given the current launch state.
      */
@@ -103,13 +80,4 @@
             return -1;
         }
     }
-
-    @Override
-    public String toString() {
-        return "RecentsActivityLaunchState altTab: " + launchedWithAltTab +
-                ", noTasks: " + launchedWithNoRecentTasks +
-                ", fromHome: " + launchedFromHome +
-                ", fromSearchHome: " + launchedFromSearchHome +
-                ", reuse: " + launchedReuseTaskStackViews;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
index 34c35a7..3412852 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
@@ -25,14 +25,14 @@
 public class HideHistoryEvent extends EventBus.Event {
 
     public final boolean animate;
-    public final ReferenceCountedTrigger postAnimationTrigger;
+    public final ReferenceCountedTrigger postHideHistoryAnimationTrigger;
 
-    public HideHistoryEvent(boolean animate) {
-        this(animate, null);
-    }
-
-    public HideHistoryEvent(boolean animate, ReferenceCountedTrigger postAnimationTrigger) {
+    /**
+     * @param postHideHistoryAnimationTrigger the trigger that gets called when all the history animations are finished
+     *                                        when transitioning from the history view
+     */
+    public HideHistoryEvent(boolean animate, ReferenceCountedTrigger postHideHistoryAnimationTrigger) {
         this.animate = animate;
-        this.postAnimationTrigger = postAnimationTrigger;
+        this.postHideHistoryAnimationTrigger = postHideHistoryAnimationTrigger;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
index 870119d..c91752e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
@@ -17,10 +17,20 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 
 /**
  * This is sent when the history view button is clicked.
  */
 public class ShowHistoryEvent extends EventBus.Event {
-    // Simple event
+
+    public final ReferenceCountedTrigger postHideStackAnimationTrigger;
+
+    /**
+     * @param postHideStackAnimationTrigger the trigger that gets called when all the task animations are finished when
+     *                                      transitioning to the history view
+     */
+    public ShowHistoryEvent(ReferenceCountedTrigger postHideStackAnimationTrigger) {
+        this.postHideStackAnimationTrigger = postHideStackAnimationTrigger;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index 2eee1da..06265bd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -110,7 +110,9 @@
         }
     }
 
+    private Context mContext;
     private LayoutInflater mLayoutInflater;
+    private final List<Task> mTasks = new ArrayList<>();
     private final List<Row> mRows = new ArrayList<>();
 
     public RecentsHistoryAdapter(Context context) {
@@ -121,6 +123,10 @@
      * Updates this adapter with the given tasks.
      */
     public void updateTasks(Context context, List<Task> tasks) {
+        mContext = context;
+        mTasks.clear();
+        mTasks.addAll(tasks);
+
         final Locale l = context.getResources().getConfiguration().locale;
         final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
         final List<Task> tasksMostRecent = new ArrayList<>(tasks);
@@ -144,6 +150,24 @@
         notifyDataSetChanged();
     }
 
+    /**
+     * Removes historical tasks beloning to the specified package and user.
+     */
+    public void removeTasks(String packageName, int userId) {
+        boolean packagesRemoved = false;
+        for (int i = mTasks.size() - 1; i >= 0; i--) {
+            Task task = mTasks.get(i);
+            String taskPackage = task.key.getComponent().getPackageName();
+            if (task.key.userId == userId && taskPackage.equals(packageName)) {
+                mTasks.remove(i);
+                packagesRemoved = true;
+            }
+        }
+        if (packagesRemoved) {
+            updateTasks(mContext, new ArrayList<Task>(mTasks));
+        }
+    }
+
     @Override
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 5851111..1163f14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.history;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
@@ -29,9 +30,18 @@
 import android.widget.LinearLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.TaskView;
+
+import java.util.ArrayList;
+import java.util.HashSet;
 
 /**
  * A list of the recent tasks that are not in the stack.
@@ -77,17 +87,21 @@
     /**
      * Updates this history view with the recent tasks, and then shows it.
      */
-    public void show(TaskStack stack) {
+    public void show(TaskStack stack, ReferenceCountedTrigger postHideAnimationTrigger) {
         setVisibility(View.VISIBLE);
         setAlpha(0f);
-        animate()
-                .alpha(1f)
-                .setDuration(mHistoryTransitionDuration)
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .withLayer()
-                .start();
-
-        mAdapter.updateTasks(getContext(), stack.computeAllTasksList());
+        postHideAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                animate()
+                        .alpha(1f)
+                        .setDuration(mHistoryTransitionDuration)
+                        .setInterpolator(mFastOutSlowInInterpolator)
+                        .withLayer()
+                        .start();
+            }
+        });
+        mAdapter.updateTasks(getContext(), stack.getHistoricalTasks());
         mIsVisible = true;
     }
 
@@ -165,8 +179,27 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+
+    @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         setSystemInsets(insets.getSystemWindowInsets());
         return insets;
     }
+
+    /**** EventBus Events ****/
+
+    public final void onBusEvent(PackagesChangedEvent event) {
+        mAdapter.removeTasks(event.packageName, event.userId);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
index 401b448..b06539a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
@@ -51,6 +51,10 @@
         }
     };
 
+    public ReferenceCountedTrigger(Context context) {
+        this(context, null, null, null);
+    }
+
     public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable,
                                    Runnable lastDecRunnable, Runnable errorRunanable) {
         mContext = context;
@@ -97,7 +101,7 @@
             if (mErrorRunnable != null) {
                 mErrorRunnable.run();
             } else {
-                Log.e(TAG, "Invalid ref count");
+                throw new RuntimeException("Invalid ref count");
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 60bedae..512effa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -93,7 +93,8 @@
 
     public TaskKey key;
     public TaskGrouping group;
-    public int taskAffiliation;
+    // The taskAffiliationId is the task id of the parent task or itself if it is not affiliated with any task
+    public int taskAffiliationId;
     public int taskAffiliationColor;
     public boolean isLaunchTarget;
     public Drawable applicationIcon;
@@ -123,7 +124,7 @@
         boolean isInAffiliationGroup = (taskAffiliation != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
         this.key = key;
-        this.taskAffiliation = taskAffiliation;
+        this.taskAffiliationId = taskAffiliation;
         this.taskAffiliationColor = taskAffiliationColor;
         this.activityLabel = activityTitle;
         this.contentDescription = contentDescription;
@@ -142,7 +143,7 @@
     /** Copies the other task. */
     public void copyFrom(Task o) {
         this.key = o.key;
-        this.taskAffiliation = o.taskAffiliation;
+        this.taskAffiliationId = o.taskAffiliationId;
         this.taskAffiliationColor = o.taskAffiliationColor;
         this.activityLabel = o.activityLabel;
         this.contentDescription = o.contentDescription;
@@ -206,6 +207,13 @@
         }
     }
 
+    /**
+     * Returns whether this task is affiliated with another task.
+     */
+    public boolean isAffiliatedTask() {
+        return key.id != taskAffiliationId;
+    }
+
     @Override
     public boolean equals(Object o) {
         // Check that the id matches
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 7a98393..13ab392 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
+import android.util.SparseArray;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsDebugFlags;
@@ -50,7 +51,7 @@
  */
 interface TaskFilter {
     /** Returns whether the filter accepts the specified task */
-    public boolean acceptTask(Task t, int index);
+    public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
 }
 
 /**
@@ -157,10 +158,17 @@
     private void updateFilteredTasks() {
         mFilteredTasks.clear();
         if (mFilter != null) {
+            // Create a sparse array from task id to Task
+            SparseArray<Task> taskIdMap = new SparseArray<>();
             int taskCount = mTasks.size();
             for (int i = 0; i < taskCount; i++) {
                 Task t = mTasks.get(i);
-                if (mFilter.acceptTask(t, i)) {
+                taskIdMap.put(t.key.id, t);
+            }
+
+            for (int i = 0; i < taskCount; i++) {
+                Task t = mTasks.get(i);
+                if (mFilter.acceptTask(taskIdMap, t, i)) {
                     mFilteredTasks.add(t);
                 }
             }
@@ -318,13 +326,29 @@
         // Ensure that we only show non-docked tasks
         mStackTaskList.setFilter(new TaskFilter() {
             @Override
-            public boolean acceptTask(Task t, int index) {
+            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
+                if (t.isAffiliatedTask()) {
+                    // If this task is affiliated with another parent in the stack, then the historical state of this
+                    // task depends on the state of the parent task
+                    Task parentTask = taskIdMap.get(t.taskAffiliationId);
+                    if (parentTask != null) {
+                        t = parentTask;
+                    }
+                }
                 return !t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
             }
         });
         mHistoryTaskList.setFilter(new TaskFilter() {
             @Override
-            public boolean acceptTask(Task t, int index) {
+            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
+                if (t.isAffiliatedTask()) {
+                    // If this task is affiliated with another parent in the stack, then the historical state of this
+                    // task depends on the state of the parent task
+                    Task parentTask = taskIdMap.get(t.taskAffiliationId);
+                    if (parentTask != null) {
+                        t = parentTask;
+                    }
+                }
                 return t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
             }
         });
@@ -585,8 +609,8 @@
                             taskGrouping2.latestActiveTimeInGroup);
                 }
             });
-            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list of
-            // tasks
+            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list
+            // of tasks
             int taskIndex = 0;
             int groupCount = mGroups.size();
             for (int i = 0; i < groupCount; i++) {
@@ -607,13 +631,13 @@
             mStackTaskList.set(tasks);
         } else {
             // Create the task groups
-            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<Task.TaskKey, Task>();
+            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<>();
             ArrayList<Task> tasks = mStackTaskList.getTasks();
             int taskCount = tasks.size();
             for (int i = 0; i < taskCount; i++) {
                 Task t = tasks.get(i);
                 TaskGrouping group;
-                int affiliation = t.taskAffiliation > 0 ? t.taskAffiliation :
+                int affiliation = t.taskAffiliationId > 0 ? t.taskAffiliationId :
                         IndividualTaskIdOffset + t.key.id;
                 if (mAffinitiesGroups.containsKey(affiliation)) {
                     group = getGroupWithAffiliation(affiliation);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 757d2aa..f646a92 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -46,19 +46,6 @@
                 }
             };
 
-    public static final Property<AnimateableViewBounds, Integer> CLIP_RIGHT =
-            new IntProperty<AnimateableViewBounds>("clipRight") {
-                @Override
-                public void setValue(AnimateableViewBounds object, int clip) {
-                    object.setClipRight(clip, false /* force */);
-                }
-
-                @Override
-                public Integer get(AnimateableViewBounds object) {
-                    return object.getClipRight();
-                }
-            };
-
     public AnimateableViewBounds(View source, int cornerRadius) {
         mSourceView = source;
         mCornerRadius = cornerRadius;
@@ -102,19 +89,6 @@
         return mClipRect.bottom;
     }
 
-    /** Sets the right clip. */
-    public void setClipRight(int right, boolean force) {
-        if (right != mClipRect.right || force) {
-            mClipRect.right = right;
-            updateClipBounds();
-        }
-    }
-
-    /** Returns the right clip. */
-    public int getClipRight() {
-        return mClipRect.right;
-    }
-
     private void updateClipBounds() {
         mClipBounds.set(mClipRect.left, mClipRect.top,
                 mSourceView.getWidth() - mClipRect.right,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 9b9d58c..2351aa3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -19,7 +19,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.Log;
-import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 
 import java.util.Collections;
@@ -80,7 +79,6 @@
                 float width = normalizedTaskWidths[i] * rowScale;
                 if (rowWidth + width > normalizedWorkspaceWidth) {
                     // That is too long for this row, create new row
-                    rowWidth = 0f;
                     if ((rowCount + 1) * rowScale > normalizedWorkspaceHeight) {
                         // The new row is too high, so we need to try fitting again.  Update the
                         // scale to be the smaller of the scale needed to fit the task in the
@@ -88,9 +86,11 @@
                         rowScale = Math.min(normalizedWorkspaceWidth / (rowWidth + width),
                                 normalizedWorkspaceHeight / (rowCount + 1));
                         rowCount = 1;
+                        rowWidth = 0;
                         i = 0;
                     } else {
                         // The new row fits, so continue
+                        rowWidth = width;
                         rowCount++;
                         i++;
                     }
@@ -103,20 +103,20 @@
             }
 
             // Normalize each of the actual rects to that scale
-            int height = (int) (rowScale * workspaceHeight);
-            float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
             float defaultRowLeft = ((1f - (maxRowWidth / normalizedWorkspaceWidth)) *
                     workspaceWidth) / 2f;
             float rowLeft = defaultRowLeft;
+            float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
+            float rowHeight = rowScale * workspaceHeight;
             for (int i = 0; i < numFreeformTasks; i++) {
                 Task task = freeformTasks.get(i);
-                int width = (int) (height * normalizedTaskWidths[i]);
+                float width = rowHeight * normalizedTaskWidths[i];
                 if (rowLeft + width > workspaceWidth) {
                     // This goes on the next line
-                    rowTop += height;
+                    rowTop += rowHeight;
                     rowLeft = defaultRowLeft;
                 }
-                RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + height);
+                RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + rowHeight);
                 rowLeft += width;
                 mTaskRectMap.put(task.key, rect);
             }
@@ -140,34 +140,29 @@
     public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut,
             TaskStackLayoutAlgorithm stackLayout) {
         if (mTaskRectMap.containsKey(task.key)) {
-            Rect taskRect = stackLayout.mTaskRect;
-            RectF ffRect = mTaskRectMap.get(task.key);
-            float scale = Math.max(ffRect.width() / taskRect.width(),
-                    ffRect.height() / taskRect.height());
-            int topOffset = (stackLayout.mFreeformRect.top - taskRect.top);
-            int scaleXOffset = (int) (((1f - scale) * taskRect.width()) / 2);
-            int scaleYOffset = (int) (((1f - scale) * taskRect.height()) / 2);
+            final Rect taskRect = stackLayout.mTaskRect;
+            final RectF ffRect = mTaskRectMap.get(task.key);
 
-            transformOut.scale = scale * 0.95f;
-            transformOut.translationX = (int) (ffRect.left - scaleXOffset);
-            transformOut.translationY = (int) (topOffset + ffRect.top - scaleYOffset);
+            transformOut.scale = 1f;
+            transformOut.alpha = 1f;
             transformOut.translationZ = stackLayout.mMaxTranslationZ;
-            transformOut.clipBottom = (int) (taskRect.height() - (ffRect.height() / scale));
-            transformOut.clipRight = (int) (taskRect.width() - (ffRect.width() / scale));
             if (task.thumbnail != null) {
-                transformOut.thumbnailScale = Math.min(
-                        ((float) taskRect.width() - transformOut.clipRight) /
-                                task.thumbnail.getWidth(),
-                        ((float) taskRect.height() - transformOut.clipBottom) /
-                                task.thumbnail.getHeight());
+                if (task.bounds == null) {
+                    // This is a stack task that has no freeform thumbnail, so keep the same bitmap
+                    // scale as it had in the stack
+                    transformOut.thumbnailScale = (float) taskRect.width() /
+                            task.thumbnail.getWidth();
+                } else {
+                    // This is a freeform rect so fit the bitmap to the task bounds
+                    transformOut.thumbnailScale = Math.min(
+                            ffRect.width() / task.thumbnail.getWidth(),
+                            ffRect.height() / task.thumbnail.getHeight());
+                }
             } else {
                 transformOut.thumbnailScale = 1f;
             }
-            transformOut.rect.set(taskRect);
-            transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
-            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
-            transformOut.rect.right -= transformOut.clipRight * scale;
-            transformOut.rect.bottom -= transformOut.clipBottom * scale;
+            transformOut.rect.set(ffRect);
+            transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
             transformOut.visible = true;
             transformOut.p = 1f;
 
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 7ae686e..addcc85 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -29,12 +27,13 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewPropertyAnimator;
 import android.view.WindowInsets;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
+import com.android.internal.logging.MetricsLogger;
+import android.widget.TextView;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
@@ -56,6 +55,7 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
@@ -76,31 +76,29 @@
     private static final String TAG = "RecentsView";
     private static final boolean DEBUG = false;
 
-    Handler mHandler;
+    private final Handler mHandler;
 
-    TaskStack mStack;
-    TaskStackView mTaskStackView;
-    RecentsAppWidgetHostView mSearchBar;
-    View mHistoryButton;
-    boolean mAwaitingFirstLayout = true;
-    boolean mLastTaskLaunchedWasFreeform;
+    private TaskStack mStack;
+    private TaskStackView mTaskStackView;
+    private RecentsAppWidgetHostView mSearchBar;
+    private TextView mHistoryButton;
+    private View mEmptyView;
+    private boolean mAwaitingFirstLayout = true;
+    private boolean mLastTaskLaunchedWasFreeform;
+    private Rect mSystemInsets = new Rect();
 
-    RecentsTransitionHelper mTransitionHelper;
-    RecentsViewTouchHandler mTouchHandler;
-    TaskStack.DockState[] mVisibleDockStates = {
+    private RecentsTransitionHelper mTransitionHelper;
+    private RecentsViewTouchHandler mTouchHandler;
+    private TaskStack.DockState[] mVisibleDockStates = {
             TaskStack.DockState.LEFT,
             TaskStack.DockState.TOP,
             TaskStack.DockState.RIGHT,
             TaskStack.DockState.BOTTOM,
     };
 
-    private Interpolator mFastOutSlowInInterpolator;
-    private Interpolator mFastOutLinearInInterpolator;
-    private int mHistoryTransitionDuration;
-
-    Rect mSystemInsets = new Rect();
-
-    final FlingAnimationUtils mFlingAnimationUtils;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private final Interpolator mFastOutLinearInInterpolator;
+    private final FlingAnimationUtils mFlingAnimationUtils;
 
     public RecentsView(Context context) {
         this(context, null);
@@ -124,25 +122,32 @@
                 com.android.internal.R.interpolator.fast_out_slow_in);
         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_linear_in);
-        mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
         mTouchHandler = new RecentsViewTouchHandler(this);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
 
         LayoutInflater inflater = LayoutInflater.from(context);
-        mHistoryButton = inflater.inflate(R.layout.recents_history_button, this, false);
+        mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
         mHistoryButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                EventBus.getDefault().send(new ShowHistoryEvent());
+                ReferenceCountedTrigger postHideStackAnimationTrigger = new ReferenceCountedTrigger(v.getContext());
+                postHideStackAnimationTrigger.increment();
+                EventBus.getDefault().send(new ShowHistoryEvent(postHideStackAnimationTrigger));
+                postHideStackAnimationTrigger.decrement();
             }
         });
+        addView(mHistoryButton);
+        mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+        addView(mEmptyView);
     }
 
     /** Set/get the bsp root node */
     public void setTaskStack(TaskStack stack) {
         RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         mStack = stack;
-        if (config.getLaunchState().launchedReuseTaskStackViews) {
+        // Disable reusing task stack views until the visibility bug is fixed. b/25998134
+        if (false && launchState.launchedReuseTaskStackViews) {
             if (mTaskStackView != null) {
                 // If onRecentsHidden is not triggered, we need to the stack view again here
                 mTaskStackView.reset();
@@ -162,10 +167,12 @@
             mTaskStackView.setCallbacks(this);
             addView(mTaskStackView);
         }
-        if (indexOfChild(mHistoryButton) == -1) {
-            addView(mHistoryButton);
+
+        // Update the top level view's visibilities
+        if (stack.getStackTaskCount() > 0) {
+            hideEmptyView();
         } else {
-            mHistoryButton.bringToFront();
+            showEmptyView();
         }
 
         // Trigger a new layout
@@ -309,13 +316,33 @@
         return mSearchBar != null && !mSearchBar.isReinflateRequired();
     }
 
-    /** Sets the visibility of the search bar */
-    public void setSearchBarVisibility(int visibility) {
+    /**
+     * Hides the task stack and shows the empty view.
+     */
+    public void showEmptyView() {
+        if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+            mSearchBar.setVisibility(View.INVISIBLE);
+        }
+        mTaskStackView.setVisibility(View.INVISIBLE);
+        mEmptyView.setVisibility(View.VISIBLE);
+        mEmptyView.bringToFront();
+        mHistoryButton.bringToFront();
+    }
+
+    /**
+     * Shows the task stack and hides the empty view.
+     */
+    public void hideEmptyView() {
+        mEmptyView.setVisibility(View.INVISIBLE);
+        mTaskStackView.setVisibility(View.VISIBLE);
+        if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+            mSearchBar.setVisibility(View.VISIBLE);
+        }
+        mTaskStackView.bringToFront();
         if (mSearchBar != null) {
-            mSearchBar.setVisibility(visibility);
-            // Always bring the search bar to the top
             mSearchBar.bringToFront();
         }
+        mHistoryButton.bringToFront();
     }
 
     /**
@@ -366,6 +393,10 @@
             mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
         }
 
+        // Measure the empty view
+        measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+
         // Measure the history button with the full space above the stack, but width-constrained
         // to the stack
         Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
@@ -373,6 +404,7 @@
                 MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(historyButtonRect.height(),
                         MeasureSpec.EXACTLY));
+
         setMeasuredDimension(width, height);
     }
 
@@ -397,6 +429,9 @@
             mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
         }
 
+        // Layout the empty view
+        mEmptyView.layout(left, top, right, bottom);
+
         // Layout the history button left-aligned with the stack, but offset from the top of the
         // view
         Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
@@ -512,6 +547,9 @@
             SystemServicesProxy ssp = Recents.getSystemServices();
             ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
             launchTask(event.task, null, INVALID_STACK_ID);
+
+            MetricsLogger.action(mContext,
+                    MetricsLogger.ACTION_WINDOW_DOCK_DRAG_DROP);
         }
     }
 
@@ -542,12 +580,21 @@
 
     public final void onBusEvent(ShowHistoryEvent event) {
         // Hide the history button when the history view is shown
-        hideHistoryButton(mHistoryTransitionDuration);
+        hideHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
+                event.postHideStackAnimationTrigger);
+        event.postHideStackAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                setAlpha(0f);
+            }
+        });
     }
 
     public final void onBusEvent(HideHistoryEvent event) {
         // Show the history button when the history view is hidden
-        showHistoryButton(mHistoryTransitionDuration);
+        setAlpha(1f);
+        showHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
+                event.postHideHistoryAnimationTrigger);
     }
 
     public final void onBusEvent(ShowHistoryButtonEvent event) {
@@ -562,31 +609,57 @@
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         if (!debugFlags.isHistoryEnabled()) {
             hideHistoryButton(100);
+        } else {
+            showHistoryButton(100);
         }
     }
 
     /**
      * Shows the history button.
      */
-    private void showHistoryButton(int duration) {
+    private void showHistoryButton(final int duration) {
+        ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(getContext());
+        postAnimationTrigger.increment();
+        showHistoryButton(duration, postAnimationTrigger);
+        postAnimationTrigger.decrement();
+    }
+
+    private void showHistoryButton(final int duration,
+            final ReferenceCountedTrigger postHideHistoryAnimationTrigger) {
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         if (!debugFlags.isHistoryEnabled()) {
             return;
         }
 
         mHistoryButton.setVisibility(View.VISIBLE);
-        mHistoryButton.animate()
-                .alpha(1f)
-                .setDuration(duration)
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .withLayer()
-                .start();
+        mHistoryButton.setAlpha(0f);
+        mHistoryButton.setText(getContext().getString(R.string.recents_history_label_format,
+                mStack.getHistoricalTasks().size()));
+        postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                mHistoryButton.animate()
+                        .alpha(1f)
+                        .setDuration(duration)
+                        .setInterpolator(mFastOutSlowInInterpolator)
+                        .withLayer()
+                        .start();
+            }
+        });
     }
 
     /**
      * Hides the history button.
      */
     private void hideHistoryButton(int duration) {
+        ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(getContext());
+        postAnimationTrigger.increment();
+        hideHistoryButton(duration, postAnimationTrigger);
+        postAnimationTrigger.decrement();
+    }
+
+    private void hideHistoryButton(int duration,
+            final ReferenceCountedTrigger postHideStackAnimationTrigger) {
         mHistoryButton.animate()
                 .alpha(0f)
                 .setDuration(duration)
@@ -595,10 +668,12 @@
                     @Override
                     public void run() {
                         mHistoryButton.setVisibility(View.INVISIBLE);
+                        postHideStackAnimationTrigger.decrement();
                     }
                 })
                 .withLayer()
                 .start();
+        postHideStackAnimationTrigger.increment();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 2920295..37a0194 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -189,7 +189,7 @@
             case MotionEvent.ACTION_CANCEL: {
                 if (mDragging) {
                     ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
-                            mRv.getContext(), null, null, null);
+                            mRv.getContext());
                     postAnimationTrigger.increment();
                     EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView,
                             mLastDropTarget, postAnimationTrigger));
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 5a09ee4..f84eb53 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -62,13 +62,14 @@
      * Prepares the scrim views for animating when entering Recents. This will be called before
      * the first draw.
      */
-    public void prepareEnterRecentsAnimation() {
+    public void prepareEnterRecentsAnimation(boolean hasStatusBarScrim, boolean animateStatusBarScrim,
+            boolean hasNavBarScrim, boolean animateNavBarScrim) {
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        mHasNavBarScrim = launchState.hasNavBarScrim();
-        mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim();
-        mHasStatusBarScrim = launchState.hasStatusBarScrim();
-        mShouldAnimateStatusBarScrim = launchState.shouldAnimateStatusBarScrim();
+        mHasNavBarScrim = hasStatusBarScrim;
+        mShouldAnimateStatusBarScrim = animateStatusBarScrim;
+        mHasStatusBarScrim = hasNavBarScrim;
+        mShouldAnimateNavBarScrim = animateNavBarScrim;
 
         mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
                 View.VISIBLE : View.INVISIBLE);
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 7d5daae..f599f52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -507,6 +507,15 @@
     }
 
     /**
+     * Returns the task progress that would put the task just off the back of the stack.
+     */
+    public float getStackBackTaskProgress(float stackScroll) {
+        float min = mUnfocusedRange.relativeMin +
+                mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
+        return stackScroll + min;
+    }
+
+    /**
      * Returns the task progress that would put the task just off the front of the stack.
      */
     public float getStackFrontTaskProgress(float stackScroll) {
@@ -647,6 +656,7 @@
             return transformOut;
         }
 
+        int x = (mStackRect.width() - mTaskRect.width()) / 2;
         int y;
         float z;
         float relP;
@@ -671,16 +681,13 @@
 
         // Fill out the transform
         transformOut.scale = 1f;
-        transformOut.translationX = (mStackRect.width() - mTaskRect.width()) / 2;
-        transformOut.translationY = y;
+        transformOut.alpha = 1f;
         transformOut.translationZ = z;
         transformOut.rect.set(mTaskRect);
-        transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
+        transformOut.rect.offset(x, y);
         Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
         transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
                 (frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
-        transformOut.clipBottom = 0;
-        transformOut.clipRight = 0;
         transformOut.thumbnailScale = 1f;
         transformOut.p = relP;
         return transformOut;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index cc5aaae..404ac47 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -20,12 +20,14 @@
 import android.animation.ValueAnimator;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.util.IntProperty;
 import android.util.Log;
 import android.util.Property;
@@ -90,19 +92,25 @@
     private final static String TAG = "TaskStackView";
     private final static boolean DEBUG = false;
 
+    private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
+    private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
+            "saved_instance_state_layout_focused_state";
+    private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
+            "saved_instance_state_layout_stack_scroll";
+
     // The thresholds at which to show/hide the history button.
     private static final float SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
     private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
 
-    public static final Property<ColorDrawable, Integer> COLOR_DRAWABLE_ALPHA =
-            new IntProperty<ColorDrawable>("colorDrawableAlpha") {
+    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
+            new IntProperty<Drawable>("drawableAlpha") {
                 @Override
-                public void setValue(ColorDrawable object, int alpha) {
+                public void setValue(Drawable object, int alpha) {
                     object.setAlpha(alpha);
                 }
 
                 @Override
-                public Integer get(ColorDrawable object) {
+                public Integer get(Drawable object) {
                     return object.getAlpha();
                 }
             };
@@ -118,7 +126,7 @@
     TaskStackViewScroller mStackScroller;
     TaskStackViewTouchHandler mTouchHandler;
     TaskStackViewCallbacks mCb;
-    ColorDrawable mFreeformWorkspaceBackground;
+    GradientDrawable mFreeformWorkspaceBackground;
     ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
     ViewPool<TaskView, Task> mViewPool;
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
@@ -126,6 +134,7 @@
     Task mFocusedTask;
     // Optimizations
     int mStackViewsAnimationDuration;
+    int mTaskCornerRadiusPx;
     boolean mStackViewsDirty = true;
     boolean mStackViewsClipDirty = true;
     boolean mAwaitingFirstLayout = true;
@@ -174,6 +183,9 @@
 
     public TaskStackView(Context context, TaskStack stack) {
         super(context);
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        Resources res = context.getResources();
+
         // Set the stack first
         setStack(stack);
         mViewPool = new ViewPool<>(context, this);
@@ -184,6 +196,8 @@
         mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
+        mTaskCornerRadiusPx = res.getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
 
         int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                 R.integer.recents_task_bar_dismiss_delay_seconds);
@@ -201,8 +215,12 @@
         });
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
 
-        mFreeformWorkspaceBackground = new ColorDrawable(0x33000000);
+        mFreeformWorkspaceBackground = (GradientDrawable) getContext().getDrawable(
+                R.drawable.recents_freeform_workspace_bg);
         mFreeformWorkspaceBackground.setCallback(this);
+        if (ssp.hasFreeformWorkspaceSupport()) {
+            setBackgroundColor(getContext().getColor(R.color.recents_freeform_workspace_bg_color));
+        }
     }
 
     /** Sets the callbacks */
@@ -364,8 +382,7 @@
     private boolean updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms,
                                        ArrayList<Task> tasks,
                                        float stackScroll,
-                                       int[] visibleRangeOut,
-                                       boolean boundTranslationsToRect) {
+                                       int[] visibleRangeOut) {
         int taskTransformCount = taskTransforms.size();
         int taskCount = tasks.size();
         int frontMostVisibleIndex = -1;
@@ -411,11 +428,6 @@
                     break;
                 }
             }
-
-            if (boundTranslationsToRect) {
-                transform.translationY = Math.min(transform.translationY,
-                        mLayoutAlgorithm.mStackRect.bottom);
-            }
             frontTransform = transform;
         }
         if (visibleRangeOut != null) {
@@ -433,7 +445,7 @@
             float stackScroll = mStackScroller.getStackScroll();
             int[] visibleStackRange = mTmpVisibleRange;
             boolean isValidVisibleStackRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
-                    stackScroll, visibleStackRange, false);
+                    stackScroll, visibleStackRange);
             boolean hasStackBackTransform = false;
             boolean hasStackFrontTransform = false;
             if (DEBUG) {
@@ -490,7 +502,7 @@
                 }
 
                 // Animate the task into place
-                tv.updateViewPropertiesToTaskTransform(transform, transform.clipBottom,
+                tv.updateViewPropertiesToTaskTransform(transform, 0,
                         mStackViewsAnimationDuration, mFastOutSlowInInterpolator,
                         mRequestUpdateClippingListener);
 
@@ -513,8 +525,9 @@
                         if (Float.compare(transform.p, 0f) <= 0) {
                             if (!hasStackBackTransform) {
                                 hasStackBackTransform = true;
-                                mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpStackBackTransform,
-                                        null);
+                                mLayoutAlgorithm.getStackTransform(
+                                        mLayoutAlgorithm.getStackBackTaskProgress(0f), 0f,
+                                        mTmpStackBackTransform, null);
                             }
                             tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0, 0,
                                     mFastOutSlowInInterpolator, mRequestUpdateClippingListener);
@@ -586,17 +599,11 @@
                 // stacked and we can make assumptions about the visibility of the this
                 // task relative to the ones in front of it.
                 if (frontTv != null) {
-                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
-                    mTmpTaskRect.offset(0, tv.getTranslationY());
-                    Utilities.scaleRectAboutCenter(mTmpTaskRect, tv.getScaleX());
-                    float taskBottom = mTmpTaskRect.bottom;
-                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
-                    mTmpTaskRect.offset(0, frontTv.getTranslationY());
-                    Utilities.scaleRectAboutCenter(mTmpTaskRect, frontTv.getScaleX());
-                    float frontTaskTop = mTmpTaskRect.top;
+                    float taskBottom = tv.getBottom();
+                    float frontTaskTop = frontTv.getTop();
                     if (frontTaskTop < taskBottom) {
                         // Map the stack view space coordinate (the rects) to view space
-                        clipBottom = (int) ((taskBottom - frontTaskTop) / tv.getScaleX()) - 1;
+                        clipBottom = (int) (taskBottom - frontTaskTop) - mTaskCornerRadiusPx;
                     }
                 }
             }
@@ -828,6 +835,24 @@
     }
 
     @Override
+    protected Parcelable onSaveInstanceState() {
+        Bundle savedState = new Bundle();
+        savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
+        savedState.putFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
+        savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
+        return super.onSaveInstanceState();
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        Bundle savedState = (Bundle) state;
+        super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
+
+        mLayoutAlgorithm.setFocusState(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
+        mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
+    }
+
+    @Override
     public CharSequence getAccessibilityClassName() {
         return TaskStackView.class.getName();
     }
@@ -980,11 +1005,11 @@
             onFirstLayout();
         }
 
+        requestSynchronizeStackViewsWithModel();
         if (changed) {
             if (mStackScroller.isScrollOutOfBounds()) {
                 mStackScroller.boundScroll();
             }
-            requestSynchronizeStackViewsWithModel();
             synchronizeStackViewsWithModel();
             requestUpdateStackViewsClip();
             clipTaskViews(true /* forceUpdate */);
@@ -1040,8 +1065,11 @@
         }
 
         // Update the history button visibility
-        if (mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+        if (shouldShowHistoryButton() &&
+                mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
             EventBus.getDefault().send(new ShowHistoryButtonEvent());
+        } else {
+            EventBus.getDefault().send(new HideHistoryButtonEvent());
         }
 
         // Start dozing
@@ -1147,8 +1175,7 @@
         transformPointToViewLocal(point, tv);
         x = point[0];
         y = point[1];
-        return (0 <= x) && (x < (tv.getMeasuredWidth() - tv.getViewBounds().getClipRight())) &&
-                (0 <= y) && (y < (tv.getMeasuredHeight() - tv.getViewBounds().getClipBottom()));
+        return (0 <= x) && (x < tv.getWidth()) && (0 <= y) && (y < tv.getHeight());
     }
 
     @Override
@@ -1221,14 +1248,13 @@
             } else if (pullStackForward) {
                 // Otherwise, offset the scroll by the movement of the anchor task
                 float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
-                float newStackScroll = mStackScroller.getStackScroll() +
-                        (anchorTaskScroll - prevAnchorTaskScroll);
+                float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
                 if (mLayoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED) {
                     // If we are focused, we don't want the front task to move, but otherwise, we
                     // allow the back task to move up, and the front task to move back
-                    newStackScroll /= 2;
+                    stackScrollOffset /= 2;
                 }
-                mStackScroller.setStackScroll(newStackScroll);
+                mStackScroller.setStackScroll(mStackScroller.getStackScroll() + stackScrollOffset);
                 mStackScroller.boundScroll();
             }
 
@@ -1372,7 +1398,8 @@
         requestSynchronizeStackViewsWithModel();
         postInvalidateOnAnimation();
 
-        if (prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
+        if (shouldShowHistoryButton() &&
+                prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
                 curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
             EventBus.getDefault().send(new ShowHistoryButtonEvent());
         } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
@@ -1498,6 +1525,18 @@
         event.taskView.animate()
                 .withEndAction(event.postAnimationTrigger.decrementAsRunnable());
 
+        // We translated the view but we need to animate it back from the current layout-space rect
+        // to its final layout-space rect
+        int x = (int) event.taskView.getTranslationX();
+        int y = (int) event.taskView.getTranslationY();
+        Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(),
+                event.taskView.getRight(), event.taskView.getBottom());
+        taskViewRect.offset(x, y);
+        event.taskView.setTranslationX(0);
+        event.taskView.setTranslationY(0);
+        event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
+                taskViewRect.right, taskViewRect.bottom);
+
         // Animate the tack view back into position
         requestSynchronizeStackViewsWithModel(250);
     }
@@ -1527,32 +1566,47 @@
     }
 
     public final void onBusEvent(ShowHistoryEvent event) {
+        // The history view's animation will be deferred until all the stack task views are animated
+        // away
+        int historyTransitionDuration =
+                getResources().getInteger(R.integer.recents_history_transition_duration);
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
         for (int i = taskViewCount - 1; i >= 0; i--) {
             TaskView tv = taskViews.get(i);
             tv.animate()
                     .alpha(0f)
-                    .setDuration(200)
+                    .setDuration(historyTransitionDuration)
                     .setUpdateListener(null)
                     .setListener(null)
                     .withLayer()
+                    .withEndAction(event.postHideStackAnimationTrigger.decrementAsRunnable())
                     .start();
+            event.postHideStackAnimationTrigger.increment();
         }
     }
 
     public final void onBusEvent(HideHistoryEvent event) {
+        // The stack task view animations will be deferred until the history view has been animated
+        // away
+        final int historyTransitionDuration =
+                getResources().getInteger(R.integer.recents_history_transition_duration);
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
         for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            tv.animate()
-                    .alpha(1f)
-                    .setDuration(200)
-                    .setUpdateListener(null)
-                    .setListener(null)
-                    .withLayer()
-                    .start();
+            final TaskView tv = taskViews.get(i);
+            event.postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    tv.animate()
+                            .alpha(1f)
+                            .setDuration(historyTransitionDuration)
+                            .setUpdateListener(null)
+                            .setListener(null)
+                            .withLayer()
+                            .start();
+                }
+            });
         }
     }
 
@@ -1582,7 +1636,7 @@
 
         Utilities.cancelAnimationWithoutCallbacks(mFreeformWorkspaceBackgroundAnimator);
         mFreeformWorkspaceBackgroundAnimator = ObjectAnimator.ofInt(mFreeformWorkspaceBackground,
-                COLOR_DRAWABLE_ALPHA, mFreeformWorkspaceBackground.getAlpha(), targetAlpha);
+                DRAWABLE_ALPHA, mFreeformWorkspaceBackground.getAlpha(), targetAlpha);
         mFreeformWorkspaceBackgroundAnimator.setDuration(duration);
         mFreeformWorkspaceBackgroundAnimator.setInterpolator(interpolator);
         mFreeformWorkspaceBackgroundAnimator.start();
@@ -1616,4 +1670,11 @@
         }
         return -1;
     }
+
+    /**
+     * @return whether the history button should be visible
+     */
+    private boolean shouldShowHistoryButton() {
+        return !mStack.getHistoricalTasks().isEmpty();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 813a1fc..1e2227e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -179,6 +179,13 @@
     }
 
     @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mHeaderView.onTaskViewSizeChanged(w, h);
+        mThumbnailView.onTaskViewSizeChanged(w, h);
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mDownTouchPos.set((int) (ev.getX() * getScaleX()), (int) (ev.getY() * getScaleY()));
@@ -232,8 +239,14 @@
             mClipAnimation.playTogether(
                     ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_BOTTOM,
                             mViewBounds.getClipBottom(), clipBottom),
-                    ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_RIGHT,
-                            mViewBounds.getClipRight(), toTransform.clipRight),
+                    ObjectAnimator.ofInt(this, TaskViewTransform.LEFT, getLeft(),
+                            (int) toTransform.rect.left),
+                    ObjectAnimator.ofInt(this, TaskViewTransform.TOP, getTop(),
+                            (int) toTransform.rect.top),
+                    ObjectAnimator.ofInt(this, TaskViewTransform.RIGHT, getRight(),
+                            (int) toTransform.rect.right),
+                    ObjectAnimator.ofInt(this, TaskViewTransform.BOTTOM, getBottom(),
+                            (int) toTransform.rect.bottom),
                     ObjectAnimator.ofFloat(mThumbnailView, TaskViewThumbnail.BITMAP_SCALE,
                             mThumbnailView.getBitmapScale(), toTransform.thumbnailScale));
             mClipAnimation.setStartDelay(toTransform.startDelay);
@@ -242,8 +255,9 @@
             mClipAnimation.start();
         } else {
             mViewBounds.setClipBottom(clipBottom, false /* forceUpdate */);
-            mViewBounds.setClipRight(toTransform.clipRight, false /* forceUpdate */);
             mThumbnailView.setBitmapScale(toTransform.thumbnailScale);
+            setLeftTopRightBottom((int) toTransform.rect.left, (int) toTransform.rect.top,
+                    (int) toTransform.rect.right, (int) toTransform.rect.bottom);
         }
         if (!config.useHardwareLayers) {
             mThumbnailView.updateThumbnailVisibility(clipBottom - getPaddingBottom());
@@ -336,10 +350,10 @@
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
-                    setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset);
+                    setTranslationY(taskViewAffiliateGroupEnterOffset);
                     setAlpha(0f);
                     animate().alpha(1f)
-                            .translationY(transform.translationY)
+                            .translationY(0)
                             .setUpdateListener(null)
                             .setListener(new AnimatorListenerAdapter() {
                                 private boolean hasEnded;
@@ -372,7 +386,7 @@
                 animate().translationZ(transform.translationZ);
             }
             animate()
-                    .translationY(transform.translationY)
+                    .translationY(0)
                     .setStartDelay(delay)
                     .setUpdateListener(ctx.updateListener)
                     .setListener(new AnimatorListenerAdapter() {
@@ -644,7 +658,6 @@
         }
 
         SystemServicesProxy ssp = Recents.getSystemServices();
-        mHeaderView.onTaskViewFocusChanged(isFocused, animated);
         if (isFocused) {
             if (requestViewFocus && !isFocused()) {
                 requestFocus();
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 78a2c7f..d8220fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -31,6 +31,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.RippleDrawable;
+import android.graphics.drawable.ShapeDrawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
@@ -55,8 +56,6 @@
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
 
-    private static final float FOCUS_TRANSLATION_Z = 4f;
-
     Task mTask;
 
     // Header views
@@ -66,13 +65,13 @@
     TextView mActivityDescription;
 
     // Header drawables
+    Rect mTaskViewRect = new Rect();
     int mCornerRadius;
     int mHighlightHeight;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
     RippleDrawable mBackground;
     GradientDrawable mBackgroundColorDrawable;
-    ObjectAnimator mFocusAnimator;
     String mDismissContentDescription;
 
     // Static highlight that we draw at the top of each view
@@ -99,13 +98,6 @@
     public TaskViewHeader(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         setWillNotDraw(false);
-        setClipToOutline(true);
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
-            }
-        });
 
         // Load the dismiss resources
         mDimLayerPaint.setColor(Color.argb(0, 0, 0, 0));
@@ -148,8 +140,8 @@
             mApplicationIcon.setBackground(null);
         }
 
-        mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(R.drawable
-                .recents_task_view_header_bg_color);
+        mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(
+                R.drawable.recents_task_view_header_bg_color);
         // Copy the ripple drawable since we are going to be manipulating it
         mBackground = (RippleDrawable)
                 getContext().getDrawable(R.drawable.recents_task_view_header_bg);
@@ -159,14 +151,37 @@
         setBackground(mBackground);
     }
 
+    /**
+     * Called when the task view frame changes, allowing us to move the contents of the header
+     * to match the frame changes.
+     */
+    public void onTaskViewSizeChanged(int width, int height) {
+        mTaskViewRect.set(0, 0, width, height);
+        if (mDismissButton.getMeasuredWidth() > (width - mApplicationIcon.getMeasuredWidth())) {
+            mDismissButton.setAlpha(0f);
+        } else {
+            mDismissButton.setAlpha(1f);
+            if (mDismissButton != null) {
+                mDismissButton.setTranslationX(width - getMeasuredWidth());
+            }
+        }
+        if (mActivityDescription.getMeasuredWidth() > (width -
+                (mApplicationIcon.getMeasuredWidth() + mDismissButton.getMeasuredWidth()))) {
+            mActivityDescription.setAlpha(0f);
+        } else {
+            mActivityDescription.setAlpha(1f);
+        }
+        invalidate();
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         // Draw the highlight at the top edge (but put the bottom edge just out of view)
         float offset = (float) Math.ceil(mHighlightHeight / 2f);
         float radius = mCornerRadius;
         int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
-        canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
-        canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
+        canvas.clipRect(0, 0, mTaskViewRect.width(), getMeasuredHeight());
+        canvas.drawRoundRect(-offset, 0f, (float) mTaskViewRect.width() + offset,
                 getMeasuredHeight() + radius, radius, radius, sHighlightPaint);
         canvas.restoreToCount(count);
     }
@@ -180,12 +195,6 @@
         invalidate();
     }
 
-    /** Returns the secondary color for a primary color. */
-    int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
-        int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
-        return Utilities.getColorWithOverlay(primaryColor, overlayColor, 0.8f);
-    }
-
     /** Binds the bar view to the task */
     public void rebindToTask(Task t) {
         mTask = t;
@@ -236,9 +245,6 @@
         mApplicationIcon.setImageDrawable(null);
         mApplicationIcon.setOnClickListener(null);
         mMoveTaskButton.setOnClickListener(null);
-
-        // Stop any focus animations
-        Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
     }
 
     /** Updates the resize task bar button. */
@@ -332,39 +338,9 @@
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
 
-        // Draw the thumbnail with the rounded corners
-        canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
-                mCornerRadius,
-                mCornerRadius, mDimLayerPaint);
-    }
-
-    /** Notifies the associated TaskView has been focused. */
-    void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) {
-        boolean isRunning = false;
-        if (mFocusAnimator != null) {
-            isRunning = mFocusAnimator.isRunning();
-        }
-        Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
-
-        if (focused) {
-            if (animateFocusedState) {
-                // Bump up the translation
-                mFocusAnimator = ObjectAnimator.ofFloat(this, "translationZ", FOCUS_TRANSLATION_Z);
-                mFocusAnimator.setDuration(200);
-                mFocusAnimator.start();
-            } else {
-                setTranslationZ(FOCUS_TRANSLATION_Z);
-            }
-        } else {
-            if (isRunning) {
-                // Restore the translation
-                mFocusAnimator = ObjectAnimator.ofFloat(this, "translationZ", 0f);
-                mFocusAnimator.setDuration(150);
-                mFocusAnimator.start();
-            } else {
-                setTranslationZ(0f);
-            }
-        }
+        // Draw the dim layer with the rounded corners
+        canvas.drawRoundRect(0, 0, mTaskViewRect.width(), getHeight(),
+                mCornerRadius, mCornerRadius, mDimLayerPaint);
     }
 
     @Override
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 7bb2c7b..37d8cd6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -56,6 +56,7 @@
             };
 
     // Drawing
+    Rect mTaskViewRect = new Rect();
     int mCornerRadius;
     float mDimAlpha;
     Matrix mScaleMatrix = new Matrix();
@@ -98,13 +99,22 @@
                 com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
+    /**
+     * Called when the task view frame changes, allowing us to move the contents of the header
+     * to match the frame changes.
+     */
+    public void onTaskViewSizeChanged(int width, int height) {
+        mTaskViewRect.set(0, 0, width, height);
+        invalidate();
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         if (mInvisible) {
             return;
         }
         // Draw the thumbnail with the rounded corners
-        canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
+        canvas.drawRoundRect(0, 0, mTaskViewRect.width(), mTaskViewRect.height(),
                 mCornerRadius,
                 mCornerRadius, mDrawPaint);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index c3e0906..3ee50ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -18,6 +18,9 @@
 
 import android.animation.ValueAnimator;
 import android.graphics.RectF;
+import android.util.IntProperty;
+import android.util.Property;
+import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.Interpolator;
 
@@ -25,26 +28,70 @@
 /* The transform state for a task view */
 public class TaskViewTransform {
 
+    public static final Property<View, Integer> LEFT =
+            new IntProperty<View>("left") {
+                @Override
+                public void setValue(View object, int v) {
+                    object.setLeft(v);
+                }
+
+                @Override
+                public Integer get(View object) {
+                    return object.getLeft();
+                }
+            };
+
+    public static final Property<View, Integer> TOP =
+            new IntProperty<View>("top") {
+                @Override
+                public void setValue(View object, int v) {
+                    object.setTop(v);
+                }
+
+                @Override
+                public Integer get(View object) {
+                    return object.getTop();
+                }
+            };
+
+    public static final Property<View, Integer> RIGHT =
+            new IntProperty<View>("right") {
+                @Override
+                public void setValue(View object, int v) {
+                    object.setRight(v);
+                }
+
+                @Override
+                public Integer get(View object) {
+                    return object.getRight();
+                }
+            };
+
+    public static final Property<View, Integer> BOTTOM =
+            new IntProperty<View>("bottom") {
+                @Override
+                public void setValue(View object, int v) {
+                    object.setBottom(v);
+                }
+
+                @Override
+                public Integer get(View object) {
+                    return object.getBottom();
+                }
+            };
+
     // TODO: Move this out of the transform
     public int startDelay = 0;
 
-    public int translationX = 0;
-    public int translationY = 0;
     public float translationZ = 0;
     public float scale = 1f;
     public float alpha = 1f;
-
-    // Clip and thumbnail scale are untransformed layout-space properties
-    // The bottom clip is only used for freeform workspace tasks
-    public int clipBottom = 0;
-    public int clipRight = 0;
     public float thumbnailScale = 1f;
 
     public boolean visible = false;
     float p = 0f;
 
-    // This is a window-space rect that is purely used for coordinating the animation of an app
-    // window into Recents.
+    // This is a window-space rect used for positioning the task in the stack and freeform workspace
     public RectF rect = new RectF();
 
     public TaskViewTransform() {
@@ -56,13 +103,9 @@
      */
     public void reset() {
         startDelay = 0;
-        translationX = 0;
-        translationY = 0;
         translationZ = 0;
         scale = 1f;
         alpha = 1f;
-        clipBottom = 0;
-        clipRight = 0;
         thumbnailScale = 1f;
         visible = false;
         rect.setEmpty();
@@ -76,12 +119,6 @@
     public boolean hasScaleChangedFrom(float v) {
         return (Float.compare(scale, v) != 0);
     }
-    public boolean hasTranslationXChangedFrom(float v) {
-        return (Float.compare(translationX, v) != 0);
-    }
-    public boolean hasTranslationYChangedFrom(float v) {
-        return (Float.compare(translationY, v) != 0);
-    }
     public boolean hasTranslationZChangedFrom(float v) {
         return (Float.compare(translationZ, v) != 0);
     }
@@ -95,12 +132,6 @@
             boolean requiresLayers = false;
 
             // Animate to the final state
-            if (hasTranslationXChangedFrom(v.getTranslationX())) {
-                anim.translationX(translationX);
-            }
-            if (hasTranslationYChangedFrom(v.getTranslationY())) {
-                anim.translationY(translationY);
-            }
             if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
                 anim.translationZ(translationZ);
             }
@@ -129,12 +160,6 @@
                     .start();
         } else {
             // Set the changed properties
-            if (hasTranslationXChangedFrom(v.getTranslationX())) {
-                v.setTranslationX(translationX);
-            }
-            if (hasTranslationYChangedFrom(v.getTranslationY())) {
-                v.setTranslationY(translationY);
-            }
             if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
                 v.setTranslationZ(translationZ);
             }
@@ -150,7 +175,8 @@
 
     /** Reset the transform on a view. */
     public static void reset(TaskView v) {
-        // Cancel any running animations
+        // Cancel any running animations and reset the translation in case something else (like a
+        // dismiss animation) changes it
         v.animate().cancel();
         v.setTranslationX(0f);
         v.setTranslationY(0f);
@@ -158,16 +184,15 @@
         v.setScaleX(1f);
         v.setScaleY(1f);
         v.setAlpha(1f);
-        v.getViewBounds().setClipRight(0, false /* forceUpdate */);
         v.getViewBounds().setClipBottom(0, false /* forceUpdate */);
+        v.setLeftTopRightBottom(0, 0, 0, 0);
         v.mThumbnailView.setBitmapScale(1f);
     }
 
     @Override
     public String toString() {
-        return "TaskViewTransform delay: " + startDelay +
-                " x: " + translationX + " y: " + translationY + " z: " + translationZ +
-                " scale: " + scale + " alpha: " + alpha + " visible: " + visible + " rect: " + rect +
-                " p: " + p;
+        return "TaskViewTransform delay: " + startDelay + " z: " + translationZ +
+                " scale: " + scale + " alpha: " + alpha + " visible: " + visible +
+                " rect: " + rect + " p: " + p;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 93264ff..c01f170 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -30,6 +30,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.View.OnTouchListener;
@@ -118,8 +119,8 @@
         updateDisplayInfo();
         boolean landscape = getResources().getConfiguration().orientation
                 == Configuration.ORIENTATION_LANDSCAPE;
-        mHandle.setPointerShape(
-                landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW);
+        mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(),
+                landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW));
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 58de5d5..ef47d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -62,7 +62,7 @@
         @Override
         public void run() {
             try {
-                ActivityManagerNative.getDefault().removeStack(DOCKED_STACK_ID);
+                ActivityManagerNative.getDefault().moveTasksToFullscreenStack(DOCKED_STACK_ID);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to remove stack: " + e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 879624e..39a33a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.statusbar;
 
+import static  android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -35,7 +38,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -82,6 +84,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
+import android.widget.SeekBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -127,8 +130,8 @@
 
     public static final boolean ENABLE_REMOTE_INPUT =
             SystemProperties.getBoolean("debug.enable_remote_input", true);
-    public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
-                    && SystemProperties.getBoolean("debug.child_notifs", false);
+    public static final boolean ENABLE_CHILD_NOTIFICATIONS
+            = SystemProperties.getBoolean("debug.child_notifs", true);
 
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -902,14 +905,6 @@
                        .findViewById(com.android.internal.R.id.media_actions) != null;
     }
 
-    // The gear button in the guts that links to the app's own notification settings
-    private void startAppOwnNotificationSettingsActivity(Intent intent,
-            final int notificationId, final String notificationTag, final int appUid) {
-        intent.putExtra("notification_id", notificationId);
-        intent.putExtra("notification_tag", notificationTag);
-        startNotificationGutsIntent(intent, appUid);
-    }
-
     // The (i) button in the guts that links to the system notification settings for that app
     private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
         final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
@@ -968,12 +963,13 @@
             // app is gone, just show package name and generic icon
             pkgicon = pmUser.getDefaultActivityIcon();
         }
+
         ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
-        ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(sbn.getPostTime());
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
+
+        bindTopicImportance(sbn, row);
+
         final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
-        final View appSettingsButton
-                = guts.findViewById(R.id.notification_inspect_app_provided_settings);
         if (appUid >= 0) {
             final int appUidF = appUid;
             settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -982,38 +978,72 @@
                     startAppNotificationSettingsActivity(pkg, appUidF);
                 }
             });
-
-            final Intent appSettingsQueryIntent
-                    = new Intent(Intent.ACTION_MAIN)
-                    .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
-                    .setPackage(pkg);
-            List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
-            if (infos.size() > 0) {
-                appSettingsButton.setVisibility(View.VISIBLE);
-                appSettingsButton.setContentDescription(
-                        mContext.getResources().getString(
-                                R.string.status_bar_notification_app_settings_title,
-                                appname
-                        ));
-                final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
-                        .setClassName(pkg, infos.get(0).activityInfo.name);
-                appSettingsButton.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        MetricsLogger.action(mContext, MetricsLogger.ACTION_APP_NOTE_SETTINGS);
-                        startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
-                                sbn.getId(),
-                                sbn.getTag(),
-                                appUidF);
-                    }
-                });
-            } else {
-                appSettingsButton.setVisibility(View.GONE);
-            }
         } else {
             settingsButton.setVisibility(View.GONE);
-            appSettingsButton.setVisibility(View.GONE);
         }
+    }
 
+    private void bindTopicImportance(final StatusBarNotification sbn,
+            ExpandableNotificationRow row) {
+        final INotificationManager sINM = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        final Notification.Topic topic = sbn.getNotification().getTopic() == null
+                ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
+                        com.android.internal.R.string.default_notification_topic_label))
+                : sbn.getNotification().getTopic();
+
+        ((TextView) row.findViewById(R.id.topic_details)).setText(topic.getLabel());
+        final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
+        int importance = mNotificationData.getImportance(sbn.getKey());
+        SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar);
+        seekBar.setMax(4);
+        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                topicSummary.setText(getProgressSummary(progress));
+                if (fromUser) {
+                    try {
+                        sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic,
+                                progress);
+                    } catch (RemoteException e) {
+                        // :(
+                    }
+                }
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+                // no-op
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+                // no-op
+            }
+
+            private String getProgressSummary(int progress) {
+                switch (progress) {
+                    case NotificationListenerService.Ranking.IMPORTANCE_NONE:
+                        return mContext.getString(
+                                com.android.internal.R.string.notification_importance_blocked);
+                    case NotificationListenerService.Ranking.IMPORTANCE_LOW:
+                        return mContext.getString(
+                                com.android.internal.R.string.notification_importance_low);
+                    case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
+                        return mContext.getString(
+                                com.android.internal.R.string.notification_importance_default);
+                    case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
+                        return mContext.getString(
+                                com.android.internal.R.string.notification_importance_high);
+                    case NotificationListenerService.Ranking.IMPORTANCE_MAX:
+                        return mContext.getString(
+                                com.android.internal.R.string.notification_importance_max);
+                    default:
+                        return "";
+                }
+            }
+        });
+        seekBar.setProgress(importance);
     }
 
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
@@ -1048,6 +1078,7 @@
 
                 MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_CONTROLS);
                 guts.setVisibility(View.VISIBLE);
+
                 final double horz = Math.max(guts.getWidth() - x, x);
                 final double vert = Math.max(guts.getActualHeight() - y, y);
                 final float r = (float) Math.hypot(horz, vert);
@@ -1292,14 +1323,13 @@
     }
 
     /**
-     * Called when the panel was layouted expanded for the first time after being collapsed.
+     * Called when the size of the notification panel changes
      */
-    public void onPanelExpandedAndLayouted() {
+    public void onPanelHeightChanged() {
         if (mState == StatusBarState.KEYGUARD) {
             // Since the number of notifications is determined based on the height of the view, we
             // need to update them.
             updateRowStates();
-            mStackScroller.onHeightChanged(null, false);
         }
     }
 
@@ -1603,7 +1633,7 @@
     private void applyRemoteInput(final Entry entry) {
         if (!ENABLE_REMOTE_INPUT) return;
 
-        RemoteInput remoteInput = null;
+        boolean hasRemoteInput = false;
 
         Notification.Action[] actions = entry.notification.getNotification().actions;
         if (actions != null) {
@@ -1611,7 +1641,7 @@
                 if (a.getRemoteInputs() != null) {
                     for (RemoteInput ri : a.getRemoteInputs()) {
                         if (ri.getAllowFreeFormInput()) {
-                            remoteInput = ri;
+                            hasRemoteInput = true;
                             break;
                         }
                     }
@@ -1619,34 +1649,50 @@
             }
         }
 
-        // See if we have somewhere to put that remote input
-        if (remoteInput != null) {
-            View bigContentView = entry.getExpandedContentView();
-            if (bigContentView != null) {
-                inflateRemoteInput(bigContentView, entry);
-            }
-            View headsUpContentView = entry.getHeadsUpContentView();
-            if (headsUpContentView != null) {
-                inflateRemoteInput(headsUpContentView, entry);
-            }
+        View bigContentView = entry.getExpandedContentView();
+        if (bigContentView != null) {
+            applyRemoteInput(bigContentView, entry, hasRemoteInput);
+        }
+        View headsUpContentView = entry.getHeadsUpContentView();
+        if (headsUpContentView != null) {
+            applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
         }
 
     }
 
-    private RemoteInputView inflateRemoteInput(View view, Entry entry) {
+    private RemoteInputView applyRemoteInput(View view, Entry entry, boolean hasRemoteInput) {
         View actionContainerCandidate = view.findViewById(
                 com.android.internal.R.id.actions_container);
         if (actionContainerCandidate instanceof FrameLayout) {
-            ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
-            RemoteInputView riv = inflateRemoteInputView(actionContainer, entry);
-            if (riv != null) {
-                riv.setVisibility(View.INVISIBLE);
-                actionContainer.addView(riv, new FrameLayout.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.MATCH_PARENT)
-                );
-                riv.setBackgroundColor(entry.notification.getNotification().color);
-                return riv;
+            RemoteInputView existing = (RemoteInputView)
+                    view.findViewWithTag(RemoteInputView.VIEW_TAG);
+
+            if (hasRemoteInput) {
+                if (existing != null) {
+                    existing.onNotificationUpdate();
+                    return existing;
+                }
+
+                ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
+                RemoteInputView riv = inflateRemoteInputView(actionContainer, entry);
+                if (riv != null) {
+                    riv.setVisibility(View.INVISIBLE);
+                    actionContainer.addView(riv, new FrameLayout.LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT)
+                    );
+                    int color = entry.notification.getNotification().color;
+                    if (color == Notification.COLOR_DEFAULT) {
+                        color = mContext.getColor(R.color.default_remote_input_background);
+                    }
+                    riv.setBackgroundColor(color);
+                    return riv;
+                }
+            } else {
+                if (existing != null) {
+                    existing.onNotificationUpdate();
+                    return null;
+                }
             }
         }
         return null;
@@ -2087,11 +2133,11 @@
         mNotificationData.updateRanking(ranking);
 
         boolean applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
-        boolean shouldInterrupt = shouldInterrupt(entry, notification);
+        boolean shouldPeek = shouldPeek(entry, notification);
         boolean alertAgain = alertAgain(entry, n);
         if (DEBUG) {
             Log.d(TAG, "applyInPlace=" + applyInPlace
-                    + " shouldInterrupt=" + shouldInterrupt
+                    + " shouldPeek=" + shouldPeek
                     + " alertAgain=" + alertAgain);
         }
 
@@ -2138,7 +2184,7 @@
             entry.icon.set(ic);
             inflateViews(entry, mStackScroller);
         }
-        updateHeadsUp(key, entry, shouldInterrupt, alertAgain);
+        updateHeadsUp(key, entry, shouldPeek, alertAgain);
         updateNotifications();
 
         // Update the veto button accordingly (and as a result, whether this row is
@@ -2154,7 +2200,7 @@
         setAreThereNotifications();
     }
 
-    protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
+    protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
             boolean alertAgain);
 
     private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
@@ -2197,49 +2243,54 @@
                 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
     }
 
-    protected boolean shouldInterrupt(Entry entry) {
-        return shouldInterrupt(entry, entry.notification);
+    protected boolean shouldPeek(Entry entry) {
+        return shouldPeek(entry, entry.notification);
     }
 
-    protected boolean shouldInterrupt(Entry entry, StatusBarNotification sbn) {
+    protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
         if (mNotificationData.shouldFilterOut(sbn)) {
-            if (DEBUG) {
-                Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out.");
-            }
+            if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
             return false;
         }
 
         if (isSnoozedPackage(sbn)) {
+            if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
             return false;
         }
 
-        Notification notification = sbn.getNotification();
-        // some predicates to make the boolean logic legible
-        boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
-                || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
-                || notification.sound != null
-                || notification.vibrate != null;
-        boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
-        boolean isFullscreen = notification.fullScreenIntent != null;
-        boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText);
-        boolean accessibilityForcesLaunch = isFullscreen
-                && mAccessibilityManager.isTouchExplorationEnabled();
-        boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent();
-        boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
-                && !accessibilityForcesLaunch
-                && !justLaunchedFullScreenIntent
-                && mPowerManager.isScreenOn()
+        if (entry.hasJustLaunchedFullScreenIntent()) {
+            if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
+            return false;
+        }
+
+        if (sbn.getNotification().fullScreenIntent != null
+                && mAccessibilityManager.isTouchExplorationEnabled()) {
+            if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
+            return false;
+        }
+
+
+        if (mNotificationData.shouldSuppressPeek(sbn.getKey())) {
+            if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+            return false;
+        }
+
+        if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_MAX) {
+            if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
+            return false;
+        }
+
+        boolean inUse = mPowerManager.isScreenOn()
                 && (!mStatusBarKeyguardViewManager.isShowing()
                         || mStatusBarKeyguardViewManager.isOccluded())
-                && !mStatusBarKeyguardViewManager.isInputRestricted()
-                && !mNotificationData.shouldSuppressPeek(sbn.getKey());
+                && !mStatusBarKeyguardViewManager.isInputRestricted();
         try {
-            interrupt = interrupt && !mDreamManager.isDreaming();
+            inUse = inUse && !mDreamManager.isDreaming();
         } catch (RemoteException e) {
             Log.d(TAG, "failed to query dream manager", e);
         }
-        if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
-        return interrupt;
+        if (DEBUG) Log.d(TAG, "peek if device in use: " + inUse);
+        return inUse;
     }
 
     protected abstract boolean isSnoozedPackage(StatusBarNotification sbn);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 10d4a96..deedae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -91,7 +91,7 @@
         public void disable(int state1, int state2, boolean animate);
         public void animateExpandNotificationsPanel();
         public void animateCollapsePanels(int flags);
-        public void animateExpandSettingsPanel();
+        public void animateExpandSettingsPanel(String obj);
         public void setSystemUiVisibility(int vis, int mask);
         public void topAppWindowChanged(boolean visible);
         public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
@@ -157,10 +157,10 @@
         }
     }
 
-    public void animateExpandSettingsPanel() {
+    public void animateExpandSettingsPanel(String subPanel) {
         synchronized (mList) {
             mHandler.removeMessages(MSG_EXPAND_SETTINGS);
-            mHandler.sendEmptyMessage(MSG_EXPAND_SETTINGS);
+            mHandler.obtainMessage(MSG_EXPAND_SETTINGS, subPanel).sendToTarget();
         }
     }
 
@@ -353,7 +353,7 @@
                     mCallbacks.animateCollapsePanels(0);
                     break;
                 case MSG_EXPAND_SETTINGS:
-                    mCallbacks.animateExpandSettingsPanel();
+                    mCallbacks.animateExpandSettingsPanel((String) msg.obj);
                     break;
                 case MSG_SET_SYSTEMUI_VISIBILITY:
                     mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5c79c7d..ed4c774 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -51,6 +51,8 @@
     private static final int COLORED_DIVIDER_ALPHA = 0x7B;
     private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
     private final int mNotificationMinHeightLegacy;
+    private final int mMaxHeadsUpHeightLegacy;
+    private final int mMaxHeadsUpHeight;
     private final int mNotificationMinHeight;
     private final int mNotificationMaxHeight;
     private int mRowMinHeight;
@@ -95,6 +97,7 @@
     private boolean mIsHeadsUp;
     private boolean mLastChronometerRunning = true;
     private NotificationHeaderView mNotificationHeader;
+    private NotificationViewWrapper mNotificationHeaderWrapper;
     private ViewStub mChildrenContainerStub;
     private NotificationGroupManager mGroupManager;
     private boolean mChildrenExpanded;
@@ -218,10 +221,15 @@
         boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
         int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
                 mNotificationMinHeightLegacy : mNotificationMinHeight;
+        boolean headsUpCustom = getPrivateLayout().getHeadsUpChild() != null &&
+                getPrivateLayout().getHeadsUpChild().getId()
+                != com.android.internal.R.id.status_bar_latest_event_content;
+        int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
+                : mMaxHeadsUpHeight;
         mRowMinHeight = minHeight;
         mMaxViewHeight = mNotificationMaxHeight;
-        mPrivateLayout.setSmallHeight(mRowMinHeight);
-        mPublicLayout.setSmallHeight(mRowMinHeight);
+        mPrivateLayout.setHeights(mRowMinHeight, headsUpheight);
+        mPublicLayout.setHeights(mRowMinHeight, headsUpheight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -385,6 +393,9 @@
     }
 
     public int getHeadsUpHeight() {
+        if (mIsSummaryWithChildren) {
+            return mChildrenContainer.getIntrinsicHeight();
+        }
         return mHeadsUpHeight;
     }
 
@@ -462,6 +473,10 @@
                 R.dimen.notification_min_height);
         mNotificationMaxHeight =  getResources().getDimensionPixelSize(
                 R.dimen.notification_max_height);
+        mMaxHeadsUpHeightLegacy =  getResources().getDimensionPixelSize(
+                R.dimen.notification_max_heads_up_height_legacy);
+        mMaxHeadsUpHeight =  getResources().getDimensionPixelSize(
+                R.dimen.notification_max_heads_up_height);
     }
 
     /**
@@ -570,6 +585,10 @@
         if (showing != null) {
             showing.setDark(dark, fade, delay);
         }
+        if (mIsSummaryWithChildren) {
+            mChildrenContainer.setDark(dark, fade, delay);
+            mNotificationHeaderWrapper.setDark(dark, fade, delay);
+        }
     }
 
     public boolean isExpandable() {
@@ -669,6 +688,9 @@
             mOnKeyguard = onKeyguard;
             logExpansionEvent(false, wasExpanded);
             if (wasExpanded != isExpanded()) {
+                if (mIsSummaryWithChildren) {
+                    mChildrenContainer.updateGroupOverflow();
+                }
                 notifyHeightChanged(false  /* needsAnimation */);
             }
         }
@@ -967,9 +989,12 @@
                     com.android.internal.R.id.expand_button);
             expandButton.setVisibility(VISIBLE);
             mNotificationHeader.setOnClickListener(mExpandClickListener);
-            addView(mNotificationHeader);
+            mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
+                    mNotificationHeader);
+            addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
         } else {
             header.reapply(getContext(), mNotificationHeader);
+            mNotificationHeaderWrapper.notifyContentUpdated();
         }
         updateHeaderExpandButton();
         updateChildrenHeaderAppearance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 51602e7..59cbd40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -44,6 +45,7 @@
     private static Rect mClipRect = new Rect();
     private boolean mWillBeGone;
     private int mMinClipTopAmount = 0;
+    private boolean mMeasuredTooHigh;
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -54,12 +56,13 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         boolean limitViewHeight = shouldLimitViewHeight();
+        final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
         int ownMaxHeight = limitViewHeight ? mMaxViewHeight : Integer.MAX_VALUE;
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
         if (hasFixedHeight) {
             // We have a height set in our layout, so we want to be at most as big as given
-            ownMaxHeight = Math.min(MeasureSpec.getSize(heightMeasureSpec), ownMaxHeight);
+            ownMaxHeight = Math.min(givenSize, ownMaxHeight);
         }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
         int maxChildHeight = 0;
@@ -97,6 +100,7 @@
         mMatchParentViews.clear();
         int width = MeasureSpec.getSize(widthMeasureSpec);
         setMeasuredDimension(width, ownHeight);
+        mMeasuredTooHigh = heightMode != MeasureSpec.UNSPECIFIED && ownHeight > givenSize;
     }
 
     protected boolean shouldLimitViewHeight() {
@@ -384,6 +388,18 @@
         mMinClipTopAmount = minClipTopAmount;
     }
 
+    @Override
+    public void setLayerType(int layerType, Paint paint) {
+        if (hasOverlappingRendering()) {
+            super.setLayerType(layerType, paint);
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return super.hasOverlappingRendering() && !mMeasuredTooHigh;
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index da01d54..2944c4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -52,7 +52,6 @@
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
 
     private final Rect mClipBounds = new Rect();
-    private final int mHeadsUpHeight;
     private final int mRoundRectRadius;
     private final Interpolator mLinearInterpolator = new LinearInterpolator();
     private final boolean mRoundRectClippingEnabled;
@@ -77,6 +76,7 @@
     private boolean mShowingLegacyBackground;
     private boolean mIsChildInGroup;
     private int mSmallHeight;
+    private int mHeadsUpHeight;
     private StatusBarNotification mStatusBarNotification;
     private NotificationGroupManager mGroupManager;
 
@@ -103,7 +103,6 @@
         super(context, attrs);
         mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
         mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
-        mHeadsUpHeight = getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
         mRoundRectRadius = getResources().getDimensionPixelSize(
                 R.dimen.notification_material_rounded_rect_radius);
         mRoundRectClippingEnabled = getResources().getBoolean(
@@ -112,8 +111,9 @@
         setOutlineProvider(mOutlineProvider);
     }
 
-    public void setSmallHeight(int smallHeight) {
+    public void setHeights(int smallHeight, int headsUpMaxHeight) {
         mSmallHeight = smallHeight;
+        mHeadsUpHeight = headsUpMaxHeight;
     }
 
     @Override
@@ -150,7 +150,7 @@
             ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
             if (layoutParams.height >= 0) {
                 // An actual height is set
-                size = Math.min(maxSize, layoutParams.height);
+                size = Math.min(size, layoutParams.height);
             }
             mHeadsUpChild.measure(widthMeasureSpec,
                     MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
@@ -283,10 +283,10 @@
     }
 
     public int getMaxHeight() {
-        if (mIsHeadsUp && mHeadsUpChild != null) {
-            return mHeadsUpChild.getHeight();
-        } else if (mExpandedChild != null) {
+        if (mExpandedChild != null) {
             return mExpandedChild.getHeight();
+        } else if (mIsHeadsUp && mHeadsUpChild != null) {
+            return mHeadsUpChild.getHeight();
         }
         return mSmallHeight;
     }
@@ -457,6 +457,9 @@
         if (mDark == dark || mContractedChild == null) return;
         mDark = dark;
         mContractedWrapper.setDark(dark && !mShowingLegacyBackground, fade, delay);
+        if (mSingleLineView != null) {
+            mSingleLineView.setDark(dark, fade, delay);
+        }
     }
 
     public void setHeadsUp(boolean headsUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 89edae3..c458d21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -188,22 +188,33 @@
         public int compare(Entry a, Entry b) {
             final StatusBarNotification na = a.notification;
             final StatusBarNotification nb = b.notification;
-            final int aPriority = na.getNotification().priority;
-            final int bPriority = nb.getNotification().priority;
+            int aImportance = Ranking.IMPORTANCE_DEFAULT;
+            int bImportance = Ranking.IMPORTANCE_DEFAULT;
+            int aRank = 0;
+            int bRank = 0;
+
+            if (mRankingMap != null) {
+                // RankingMap as received from NoMan
+                mRankingMap.getRanking(a.key, mRankingA);
+                mRankingMap.getRanking(b.key, mRankingB);
+                aImportance = mRankingA.getImportance();
+                bImportance = mRankingB.getImportance();
+                aRank = mRankingA.getRank();
+                bRank = mRankingB.getRank();
+            }
 
             String mediaNotification = mEnvironment.getCurrentMediaNotificationKey();
 
             // PRIORITY_MIN media streams are allowed to drift to the bottom
             final boolean aMedia = a.key.equals(mediaNotification)
-                    && aPriority > Notification.PRIORITY_MIN;
+                    && aImportance > Ranking.IMPORTANCE_LOW;
             final boolean bMedia = b.key.equals(mediaNotification)
-                    && bPriority > Notification.PRIORITY_MIN;
+                    && bImportance > Ranking.IMPORTANCE_LOW;
 
-            boolean aSystemMax = aPriority >= Notification.PRIORITY_MAX &&
+            boolean aSystemMax = aImportance >= Ranking.IMPORTANCE_MAX &&
                     isSystemNotification(na);
-            boolean bSystemMax = bPriority >= Notification.PRIORITY_MAX &&
+            boolean bSystemMax = bImportance >= Ranking.IMPORTANCE_MAX &&
                     isSystemNotification(nb);
-            int d = nb.getScore() - na.getScore();
 
             boolean isHeadsUp = a.row.isHeadsUp();
             if (isHeadsUp != b.row.isHeadsUp()) {
@@ -217,13 +228,8 @@
             } else if (aSystemMax != bSystemMax) {
                 // Upsort PRIORITY_MAX system notifications
                 return aSystemMax ? -1 : 1;
-            } else if (mRankingMap != null) {
-                // RankingMap as received from NoMan
-                mRankingMap.getRanking(a.key, mRankingA);
-                mRankingMap.getRanking(b.key, mRankingB);
-                return mRankingA.getRank() - mRankingB.getRank();
-            } if (d != 0) {
-                return d;
+            } else if (aRank != bRank) {
+                return aRank - bRank;
             } else {
                 return (int) (nb.getNotification().when - na.getNotification().when);
             }
@@ -283,7 +289,7 @@
             mRankingMap.getRanking(key, mTmpRanking);
             return mTmpRanking.getVisibilityOverride();
         }
-        return NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+        return Ranking.VISIBILITY_NO_OVERRIDE;
     }
 
     public boolean shouldSuppressPeek(String key) {
@@ -295,6 +301,14 @@
         return false;
     }
 
+    public int getImportance(String key) {
+        if (mRankingMap != null) {
+            mRankingMap.getRanking(key, mTmpRanking);
+            return mTmpRanking.getImportance();
+        }
+        return Ranking.IMPORTANCE_UNSPECIFIED;
+    }
+
     private void updateRankingAndSort(RankingMap ranking) {
         if (ranking != null) {
             mRankingMap = ranking;
@@ -390,12 +404,13 @@
     }
 
     private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) {
+        mRankingMap.getRanking(e.key, mTmpRanking);
         pw.print(indent);
         pw.println("  [" + i + "] key=" + e.key + " icon=" + e.icon);
         StatusBarNotification n = e.notification;
         pw.print(indent);
-        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " score=" +
-                n.getScore());
+        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" +
+                mTmpRanking.getImportance());
         pw.print(indent);
         pw.println("      notification=" + n.getNotification());
         pw.print(indent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 46e0bf8..0081496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -21,12 +21,14 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
 import com.android.systemui.R;
 
 /**
  * The guts of a notification revealed when performing a long press.
  */
-public class NotificationGuts extends FrameLayout {
+public class NotificationGuts extends LinearLayout {
 
     private Drawable mBackground;
     private int mClipTopAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java
new file mode 100644
index 0000000..ddad2e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.view.NotificationHeaderView;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+import java.util.ArrayList;
+
+/**
+ * Wraps a notification header view.
+ */
+public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
+
+    private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
+    private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
+            0, PorterDuff.Mode.SRC_ATOP);
+    private final int mIconDarkAlpha;
+    private final int mIconDarkColor = 0xffffffff;
+    protected final Interpolator mLinearOutSlowInInterpolator;
+    protected final ViewInvertHelper mInvertHelper;
+
+    protected int mColor;
+    private ImageView mIcon;
+
+    private ImageView mExpandButton;
+    private NotificationHeaderView mNotificationHeader;
+
+    protected NotificationHeaderViewWrapper(Context ctx, View view) {
+        super(view);
+        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
+                android.R.interpolator.linear_out_slow_in);
+        mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
+        resolveHeaderViews();
+    }
+
+    protected void resolveHeaderViews() {
+        mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+        mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
+        mColor = resolveColor(mExpandButton);
+        mNotificationHeader = (NotificationHeaderView) mView.findViewById(
+                com.android.internal.R.id.notification_header);
+        for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
+            View child = mNotificationHeader.getChildAt(i);
+            if (child != mIcon) {
+                mInvertHelper.addTarget(child);
+            }
+        }
+    }
+
+    private int resolveColor(ImageView icon) {
+        if (icon != null && icon.getDrawable() != null) {
+            ColorFilter filter = icon.getDrawable().getColorFilter();
+            if (filter instanceof PorterDuffColorFilter) {
+                return ((PorterDuffColorFilter) filter).getColor();
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public void notifyContentUpdated() {
+        mInvertHelper.clearTargets();
+        // Reinspect the notification.
+        resolveHeaderViews();
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (fade) {
+            mInvertHelper.fade(dark, delay);
+        } else {
+            mInvertHelper.update(dark);
+        }
+        if (mIcon != null) {
+            boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
+                    != NotificationHeaderView.NO_COLOR;
+            if (fade) {
+                if (hadColorFilter) {
+                    fadeIconColorFilter(mIcon, dark, delay);
+                    fadeIconAlpha(mIcon, dark, delay);
+                } else {
+                    fadeGrayscale(mIcon, dark, delay);
+                }
+            } else {
+                if (hadColorFilter) {
+                    updateIconColorFilter(mIcon, dark);
+                    updateIconAlpha(mIcon, dark);
+                } else {
+                    updateGrayscale(mIcon, dark);
+                }
+            }
+        }
+    }
+
+    protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+            boolean dark, long delay, Animator.AnimatorListener listener) {
+        float startIntensity = dark ? 0f : 1f;
+        float endIntensity = dark ? 1f : 0f;
+        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+        animator.addUpdateListener(updateListener);
+        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+        animator.setInterpolator(mLinearOutSlowInInterpolator);
+        animator.setStartDelay(delay);
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        animator.start();
+    }
+
+    private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = (float) animation.getAnimatedValue();
+                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateGrayscaleMatrix((float) animation.getAnimatedValue());
+                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+            }
+        }, dark, delay, new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!dark) {
+                    target.setColorFilter(null);
+                }
+            }
+        });
+    }
+
+    private void updateIconColorFilter(ImageView target, boolean dark) {
+        updateIconColorFilter(target, dark ? 1f : 0f);
+    }
+
+    private void updateIconColorFilter(ImageView target, float intensity) {
+        int color = interpolateColor(mColor, mIconDarkColor, intensity);
+        mIconColorFilter.setColor(color);
+        Drawable iconDrawable = target.getDrawable();
+
+        // Also, the notification might have been modified during the animation, so background
+        // might be null here.
+        if (iconDrawable != null) {
+            iconDrawable.mutate().setColorFilter(mIconColorFilter);
+        }
+    }
+
+    private void updateIconAlpha(ImageView target, boolean dark) {
+        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
+    }
+
+    protected void updateGrayscale(ImageView target, boolean dark) {
+        if (dark) {
+            updateGrayscaleMatrix(1f);
+            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+        } else {
+            target.setColorFilter(null);
+        }
+    }
+
+    @Override
+    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
+        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
+        mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
+    }
+
+    private void updateGrayscaleMatrix(float intensity) {
+        mGrayscaleColorMatrix.setSaturation(1 - intensity);
+    }
+
+    private static int interpolateColor(int source, int target, float t) {
+        int aSource = Color.alpha(source);
+        int rSource = Color.red(source);
+        int gSource = Color.green(source);
+        int bSource = Color.blue(source);
+        int aTarget = Color.alpha(target);
+        int rTarget = Color.red(target);
+        int gTarget = Color.green(target);
+        int bTarget = Color.blue(target);
+        return Color.argb(
+                (int) (aSource * (1f - t) + aTarget * t),
+                (int) (rSource * (1f - t) + rTarget * t),
+                (int) (gSource * (1f - t) + gTarget * t),
+                (int) (bSource * (1f - t) + bTarget * t));
+    }
+
+    @Override
+    public NotificationHeaderView getNotificationHeader() {
+        return mNotificationHeader;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
index fb0a419..77e8c55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -16,74 +16,31 @@
 
 package com.android.systemui.statusbar;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.view.MotionEvent;
-import android.view.NotificationHeaderView;
 import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
-import java.util.ArrayList;
 
 /**
  * Wraps a notification view inflated from a template.
  */
-public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
+public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
 
-    private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
-    private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
-            0, PorterDuff.Mode.SRC_ATOP);
-    private final int mIconDarkAlpha;
-    private final int mIconDarkColor = 0xffffffff;
-    private final int mDarkProgressTint = 0xffffffff;
-    private final Interpolator mLinearOutSlowInInterpolator;
+    private static final int mDarkProgressTint = 0xffffffff;
 
-    private int mColor;
-    private ViewInvertHelper mInvertHelper;
-    private ImageView mIcon;
     protected ImageView mPicture;
-
-    private ImageView mExpandButton;
-    private NotificationHeaderView mNotificationHeader;
     private ProgressBar mProgressBar;
 
     protected NotificationTemplateViewWrapper(Context ctx, View view) {
-        super(view);
-        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
-                android.R.interpolator.linear_out_slow_in);
-
-        resolveViews();
+        super(ctx, view);
+        resolveTemplateViews();
     }
 
-    private void resolveViews() {
+    private void resolveTemplateViews() {
         View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
-        mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
         mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
-        mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
-        mColor = resolveColor(mExpandButton);
         final View progress = mView.findViewById(com.android.internal.R.id.progress);
         if (progress instanceof ProgressBar) {
             mProgressBar = (ProgressBar) progress;
@@ -91,30 +48,9 @@
             // It's still a viewstub
             mProgressBar = null;
         }
-        mNotificationHeader = (NotificationHeaderView) mView.findViewById(
-                com.android.internal.R.id.notification_header);
-        ArrayList<View> viewsToInvert = new ArrayList<>();
         if (mainColumn != null) {
-            viewsToInvert.add(mainColumn);
+            mInvertHelper.addTarget(mainColumn);
         }
-        for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
-            View child = mNotificationHeader.getChildAt(i);
-            if (child != mIcon) {
-                viewsToInvert.add(child);
-            }
-        }
-        mInvertHelper = new ViewInvertHelper(viewsToInvert,
-                NotificationPanelView.DOZE_ANIMATION_DURATION);
-    }
-
-    private int resolveColor(ImageView icon) {
-        if (icon != null && icon.getDrawable() != null) {
-            ColorFilter filter = icon.getDrawable().getColorFilter();
-            if (filter instanceof PorterDuffColorFilter) {
-                return ((PorterDuffColorFilter) filter).getColor();
-            }
-        }
-        return 0;
     }
 
     @Override
@@ -122,37 +58,12 @@
         super.notifyContentUpdated();
 
         // Reinspect the notification.
-        resolveViews();
+        resolveTemplateViews();
     }
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
-        if (mInvertHelper != null) {
-            if (fade) {
-                mInvertHelper.fade(dark, delay);
-            } else {
-                mInvertHelper.update(dark);
-            }
-        }
-        if (mIcon != null) {
-            boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
-                    != NotificationHeaderView.NO_COLOR;
-            if (fade) {
-                if (hadColorFilter) {
-                    fadeIconColorFilter(mIcon, dark, delay);
-                    fadeIconAlpha(mIcon, dark, delay);
-                } else {
-                    fadeGrayscale(mIcon, dark, delay);
-                }
-            } else {
-                if (hadColorFilter) {
-                    updateIconColorFilter(mIcon, dark);
-                    updateIconAlpha(mIcon, dark);
-                } else {
-                    updateGrayscale(mIcon, dark);
-                }
-            }
-        }
+        super.setDark(dark, fade, delay);
         setPictureGrayscale(dark, fade, delay);
         setProgressBarDark(dark, fade, delay);
     }
@@ -197,96 +108,6 @@
         }
     }
 
-    private void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
-            boolean dark, long delay, Animator.AnimatorListener listener) {
-        float startIntensity = dark ? 0f : 1f;
-        float endIntensity = dark ? 1f : 0f;
-        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
-        animator.addUpdateListener(updateListener);
-        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
-        animator.setInterpolator(mLinearOutSlowInInterpolator);
-        animator.setStartDelay(delay);
-        if (listener != null) {
-            animator.addListener(listener);
-        }
-        animator.start();
-    }
-
-    private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (float) animation.getAnimatedValue();
-                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateGrayscaleMatrix((float) animation.getAnimatedValue());
-                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-            }
-        }, dark, delay, new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!dark) {
-                    target.setColorFilter(null);
-                }
-            }
-        });
-    }
-
-    private void updateIconColorFilter(ImageView target, boolean dark) {
-        updateIconColorFilter(target, dark ? 1f : 0f);
-    }
-
-    private void updateIconColorFilter(ImageView target, float intensity) {
-        int color = interpolateColor(mColor, mIconDarkColor, intensity);
-        mIconColorFilter.setColor(color);
-        Drawable iconDrawable = target.getDrawable();
-
-        // Also, the notification might have been modified during the animation, so background
-        // might be null here.
-        if (iconDrawable != null) {
-            iconDrawable.mutate().setColorFilter(mIconColorFilter);
-        }
-    }
-
-    private void updateIconAlpha(ImageView target, boolean dark) {
-        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
-    }
-
-    protected void updateGrayscale(ImageView target, boolean dark) {
-        if (dark) {
-            updateGrayscaleMatrix(1f);
-            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-        } else {
-            target.setColorFilter(null);
-        }
-    }
-
-    @Override
-    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
-        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
-        mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
-    }
-
-    private void updateGrayscaleMatrix(float intensity) {
-        mGrayscaleColorMatrix.setSaturation(1 - intensity);
-    }
-
     private static int interpolateColor(int source, int target, float t) {
         int aSource = Color.alpha(source);
         int rSource = Color.red(source);
@@ -302,9 +123,4 @@
                 (int) (gSource * (1f - t) + gTarget * t),
                 (int) (bSource * (1f - t) + bTarget * t));
     }
-
-    @Override
-    public NotificationHeaderView getNotificationHeader() {
-        return mNotificationHeader;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index 119d57b..61499de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -26,16 +26,13 @@
  */
 public abstract class NotificationViewWrapper {
 
-    private static final String TAG_BIG_MEDIA_NARROW = "bigMediaNarrow";
-    private static final String TAG_MEDIA = "media";
-    private static final String TAG_BIG_PICTURE = "bigPicture";
-
     protected final View mView;
-    private boolean mSubTextVisible = true;
 
     public static NotificationViewWrapper wrap(Context ctx, View v) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
             return new NotificationTemplateViewWrapper(ctx, v);
+        } else if (v instanceof NotificationHeaderView) {
+            return new NotificationHeaderViewWrapper(ctx, v);
         } else {
             return new NotificationCustomViewWrapper(v);
         }
@@ -57,9 +54,7 @@
     /**
      * Notifies this wrapper that the content of the view might have changed.
      */
-    public void notifyContentUpdated() {
-        setSubTextVisible(mSubTextVisible);
-    }
+    public void notifyContentUpdated() {};
 
     /**
      * @return true if this template might need to be clipped with a round rect to make it look
@@ -70,14 +65,6 @@
     }
 
     /**
-     * Change the subTextVisibility
-     * @param visible Should the subtext be visible
-     */
-    public void setSubTextVisible(boolean visible) {
-        mSubTextVisible = visible;
-    }
-
-    /**
      * Update the appearance of the expand button.
      *
      * @param expandable should this view be expandable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index fafea98..5fb6fec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -23,6 +23,8 @@
 
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
  * A hybrid view which may contain information about one ore more notifications.
@@ -31,6 +33,7 @@
 
     protected TextView mTitleView;
     protected TextView mTextView;
+    private ViewInvertHelper mInvertHelper;
 
     public HybridNotificationView(Context context) {
         this(context, null);
@@ -54,6 +57,7 @@
         super.onFinishInflate();
         mTitleView = (TextView) findViewById(R.id.notification_title);
         mTextView = (TextView) findViewById(R.id.notification_text);
+        mInvertHelper = new ViewInvertHelper(this, NotificationPanelView.DOZE_ANIMATION_DURATION);
     }
 
     public void bind(CharSequence title) {
@@ -65,4 +69,8 @@
         mTextView.setText(text);
         requestLayout();
     }
+
+    public void setDark(boolean dark, boolean fade, long delay) {
+        mInvertHelper.setInverted(dark, fade, delay);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index a2616fe..79bd626 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -25,6 +25,7 @@
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.stackdivider.Divider;
@@ -58,7 +59,6 @@
 
     private final GestureDetector mTaskSwitcherDetector;
     private final int mScrollTouchSlop;
-    private final int mTouchSlop;
     private final int mMinFlingVelocity;
     private int mTouchDownX;
     private int mTouchDownY;
@@ -73,7 +73,6 @@
         ViewConfiguration configuration = ViewConfiguration.get(context);
         Resources r = context.getResources();
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
         mTaskSwitcherDetector = new GestureDetector(context, this);
         TunerService.get(context).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
@@ -167,8 +166,8 @@
         int yDiff = Math.abs(y - mTouchDownY);
         if (!mDockWindowTouchSlopExceeded) {
             boolean touchSlopExceeded = !mIsVertical
-                    ? yDiff > mTouchSlop && yDiff > xDiff
-                    : xDiff > mTouchSlop && xDiff > yDiff;
+                    ? yDiff > mScrollTouchSlop && yDiff > xDiff
+                    : xDiff > mScrollTouchSlop && xDiff > yDiff;
             if (touchSlopExceeded && mDivider.getView().getWindowManagerProxy().getDockSide()
                     == DOCKED_INVALID) {
                 mDragMode = calculateDragMode();
@@ -193,6 +192,8 @@
                     mDivider.getView().startDragging();
                 }
                 mDockWindowTouchSlopExceeded = true;
+                MetricsLogger.action(mContext,
+                        MetricsLogger.ACTION_WINDOW_DOCK_SWIPE);
                 return true;
             }
         } else {
@@ -270,7 +271,7 @@
     public void onTuningChanged(String key, String newValue) {
         switch (key) {
             case KEY_DOCK_WINDOW_GESTURE:
-                mDockWindowEnabled = (newValue != null) &&
+                mDockWindowEnabled = (newValue == null) ||
                         (Integer.parseInt(newValue) != 0);
                 break;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 73ee363..42fd872 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -44,7 +44,6 @@
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.TextView;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.DejankUtils;
@@ -65,7 +64,6 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
-import com.android.systemui.tuner.TunerService;
 
 import java.util.List;
 
@@ -73,7 +71,7 @@
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
-        HeadsUpManager.OnHeadsUpChangedListener, TunerService.Tunable {
+        HeadsUpManager.OnHeadsUpChangedListener {
 
     private static final boolean DEBUG = false;
 
@@ -221,13 +219,10 @@
     private final Interpolator mTouchResponseInterpolator =
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
 
-    private boolean mNewQs;
-
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setWillNotDraw(!DEBUG);
         mFalsingManager = FalsingManager.getInstance(context);
-        TunerService.get(context).addTunable(this, QSPanel.QS_THE_NEW_QS);
     }
 
     public void setStatusBar(PhoneStatusBar bar) {
@@ -235,26 +230,10 @@
     }
 
     @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (QSPanel.QS_THE_NEW_QS.equals(key)) {
-            boolean b = newValue != null && Integer.parseInt(newValue) != 0;
-            if (mNewQs != b) {
-                if (mHeader != null) {
-                    // We are too late, no good way to re-initialize yet, just die and come back up.
-                    android.os.Process.killProcess(android.os.Process.myPid());
-                } else {
-                    mNewQs = b;
-                }
-            }
-        }
-    }
-
-    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         ViewStub stub = (ViewStub) findViewById(R.id.status_bar_header);
-        stub.setLayoutResource(mNewQs
-                ? R.layout.quick_status_bar_expanded_header : R.layout.status_bar_expanded_header);
+        stub.setLayoutResource(R.layout.quick_status_bar_expanded_header);
         mHeader = (BaseStatusBarHeader) stub.inflate();
         mHeader.setOnClickListener(this);
         mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
@@ -373,8 +352,6 @@
         }
         updateStackHeight(getExpandedHeight());
         updateHeader();
-        mNotificationStackScroller.updateIsSmallScreen(
-                mHeader.getCollapsedHeight() + mQsPeekHeight);
 
         // If we are running a size change animation, the animation takes care of the height of
         // the container. However, if we are not animating, we always need to make the QS container
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 21d803d..5e54ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -82,6 +82,7 @@
     private boolean mMotionAborted;
     private boolean mUpwardsWhenTresholdReached;
     private boolean mAnimatingOnDown;
+    private int mLayoutHeight = 0;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -716,6 +717,10 @@
     @Override
     protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
+        if (mLayoutHeight != getHeight()) {
+            mLayoutHeight = getHeight();
+            mStatusBar.onPanelHeightChanged();
+        }
         requestPanelHeightUpdate();
         mHasLayoutedSinceDown = true;
         if (mUpdateFlingOnLayout) {
@@ -889,7 +894,6 @@
                         if (mStatusBar.getStatusBarWindow().getHeight()
                                 != mStatusBar.getStatusBarHeight()) {
                             getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                            mStatusBar.onPanelExpandedAndLayouted();
                             if (animate) {
                                 mBar.startOpeningPanel(PanelView.this);
                                 notifyExpandingStarted();
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 181e6aa..8f7c95e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1136,6 +1136,8 @@
                 mRecents.dockTopTask(false /* draggingInRecents */,
                         ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
                         null /* initialBounds */);
+                MetricsLogger.action(mContext,
+                        MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS);
                 return true;
             }
             return false;
@@ -1266,7 +1268,7 @@
         if (shadeEntry == null) {
             return;
         }
-        boolean isHeadsUped = mUseHeadsUp && shouldInterrupt(shadeEntry);
+        boolean isHeadsUped = mUseHeadsUp && shouldPeek(shadeEntry);
         if (isHeadsUped) {
             mHeadsUpManager.showNotification(shadeEntry);
             // Mark as seen immediately
@@ -2111,17 +2113,17 @@
 
     }
 
-    protected void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
+    protected void updateHeadsUp(String key, Entry entry, boolean shouldPeek,
             boolean alertAgain) {
         final boolean wasHeadsUp = isHeadsUp(key);
         if (wasHeadsUp) {
-            if (!shouldInterrupt) {
+            if (!shouldPeek) {
                 // We don't want this to be interrupting anymore, lets remove it
                 mHeadsUpManager.removeNotification(key);
             } else {
                 mHeadsUpManager.updateNotification(entry, alertAgain);
             }
-        } else if (shouldInterrupt && alertAgain) {
+        } else if (shouldPeek && alertAgain) {
             // This notification was updated to be a heads-up, show it!
             mHeadsUpManager.showNotification(entry);
         }
@@ -2160,7 +2162,7 @@
                     animateExpandNotificationsPanel();
                     break;
                 case MSG_OPEN_SETTINGS_PANEL:
-                    animateExpandSettingsPanel();
+                    animateExpandSettingsPanel((String) m.obj);
                     break;
                 case MSG_CLOSE_PANELS:
                     animateCollapsePanels();
@@ -2303,7 +2305,7 @@
     }
 
     @Override
-    public void animateExpandSettingsPanel() {
+    public void animateExpandSettingsPanel(String subPanel) {
         if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
         if (!panelsEnabled()) {
             return;
@@ -2312,6 +2314,10 @@
         // Settings are not available in setup
         if (!mUserSetup) return;
 
+
+        if (subPanel != null) {
+            mQSPanel.openDetails(subPanel);
+        }
         mNotificationPanel.expandWithQs();
 
         if (false) postStartTracing();
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 c740b08..7f27ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -133,7 +133,7 @@
         TunerService.get(mContext).addTunable(this, TILES_SETTING);
     }
 
-    PhoneStatusBar getPhoneStatusBar() {
+    public PhoneStatusBar getPhoneStatusBar() {
         return mStatusBar;
     }
 
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 26ff97a..1372cca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -24,12 +24,14 @@
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.Switch;
 import android.widget.TextView;
 import android.widget.Toast;
+import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
@@ -42,6 +44,7 @@
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
         NextAlarmController.NextAlarmChangeCallback, View.OnClickListener {
 
+    private static final String TAG = "QuickStatusBarHeader";
     private ActivityStarter mActivityStarter;
     private NextAlarmController mNextAlarmController;
     private SettingsButton mSettingsButton;
@@ -59,11 +62,15 @@
 
     private boolean mDetailTransitioning;
     private ViewGroup mExpandedGroup;
+    private ViewGroup mDateTimeGroup;
+    private View mEmergencyOnly;
     private TextView mQsDetailHeaderTitle;
     private boolean mListening;
     private AlarmManager.AlarmClockInfo mNextAlarm;
 
     private QuickQSPanel mHeaderQsPanel;
+    private boolean mShowEmergencyCallsOnly;
+    private float mDateTimeTranslation;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -73,6 +80,10 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
+        mEmergencyOnly = findViewById(R.id.header_emergency_calls_only);
+        mDateTimeTranslation = mContext.getResources().getDimension(
+                R.dimen.qs_date_anim_translation);
+        mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
         mExpandedGroup = (ViewGroup) findViewById(R.id.expanded_group);
 
         mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel);
@@ -118,14 +129,15 @@
     @Override
     public void setExpanded(boolean expanded) {
         mExpanded = expanded;
+        updateEverything();
     }
 
     @Override
     public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
         mNextAlarm = nextAlarm;
+        Log.d(TAG, "Got alarm update " + (nextAlarm != null));
         if (nextAlarm != null) {
-            // TODO:...
-//            mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
+            mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
         }
         mAlarmShowing = nextAlarm != null;
         updateEverything();
@@ -137,6 +149,9 @@
         mExpandedGroup.setVisibility(headerExpansionFraction > 0 ? View.VISIBLE : View.INVISIBLE);
         mHeaderQsPanel.setAlpha(1 - headerExpansionFraction);
         mHeaderQsPanel.setVisibility(headerExpansionFraction < 1 ? View.VISIBLE : View.INVISIBLE);
+
+        mDateTimeGroup.setTranslationY(headerExpansionFraction * mDateTimeTranslation);
+        mEmergencyOnly.setAlpha(headerExpansionFraction);
     }
 
     public void setListening(boolean listening) {
@@ -154,16 +169,20 @@
     }
 
     private void updateVisibilities() {
-        mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.GONE);
+        mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE);
         mQsDetailHeader.setVisibility(mExpanded && mShowingDetail ? View.VISIBLE : View.INVISIBLE);
+        mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly
+                ? View.VISIBLE : View.INVISIBLE);
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
                 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
     }
 
     private void updateListeners() {
         if (mListening) {
+            Log.d(TAG, "Listening for Alarms");
             mNextAlarmController.addStateChangedCallback(this);
         } else {
+            Log.d(TAG, "Not listening for Alarms");
             mNextAlarmController.removeStateChangedCallback(this);
         }
     }
@@ -193,7 +212,7 @@
                 host.getBatteryController());
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
         mHeaderQsPanel.setHost(myHost);
-        mHeaderQsPanel.setMaxTiles(3);
+        mHeaderQsPanel.setMaxTiles(5);
         mHeaderQsPanel.setTiles(myHost.getTiles());
         myHost.addCallback(new QSTile.Host.Callback() {
             @Override
@@ -250,8 +269,14 @@
     }
 
     @Override
-    public void setEmergencyCallsOnly(boolean emergencyOnly) {
-        // Don't care.
+    public void setEmergencyCallsOnly(boolean show) {
+        boolean changed = show != mShowEmergencyCallsOnly;
+        if (changed) {
+            mShowEmergencyCallsOnly = show;
+            if (mExpanded) {
+                updateEverything();
+            }
+        }
     }
 
     private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
@@ -308,6 +333,7 @@
 
         private void handleShowingDetail(final QSTile.DetailAdapter detail) {
             final boolean showingDetail = detail != null;
+            transition(mDateTimeGroup, !showingDetail);
             transition(mExpandedGroup, !showingDetail);
             if (mAlarmShowing) {
                 transition(mAlarmStatus, !showingDetail);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 6cda561..3d21f44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -59,7 +59,7 @@
  */
 public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnClickListener,
         BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback,
-        EmergencyListener, TunerService.Tunable {
+        EmergencyListener {
 
     private boolean mExpanded;
     private boolean mListening;
@@ -234,28 +234,6 @@
         updateClockCollapsedMargin();
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        TunerService.get(mContext).addTunable(this, QSPanel.QS_THE_NEW_QS);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        TunerService.get(mContext).removeTunable(this);
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (QSPanel.QS_THE_NEW_QS.equals(key)) {
-            mAllowExpand = newValue == null || Integer.parseInt(newValue) == 0;
-            if (!mAllowExpand) {
-                setExpanded(false);
-            }
-        }
-    }
-
     private void updateClockCollapsedMargin() {
         Resources res = getResources();
         int padding = res.getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin);
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 22c0cb9..65053f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -28,6 +28,8 @@
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -49,7 +51,7 @@
 /**
  * Host for the remote input.
  */
-public class RemoteInputView extends LinearLayout implements View.OnClickListener {
+public class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {
 
     private static final String TAG = "RemoteInput";
 
@@ -101,6 +103,7 @@
             }
         });
         mEditText.setOnClickListener(this);
+        mEditText.addTextChangedListener(this);
         mEditText.setInnerFocusable(false);
         mEditText.mDefocusListener = this;
     }
@@ -115,6 +118,8 @@
         mEditText.setEnabled(false);
         mSendButton.setVisibility(INVISIBLE);
         mProgressBar.setVisibility(VISIBLE);
+        mController.removeRemoteInput(mEntry);
+        mEditText.mShowImeOnInputConnection = false;
 
         try {
             mPendingIntent.send(mContext, 0, fillInIntent);
@@ -175,6 +180,40 @@
         mEditText.setText(mEntry.remoteInputText);
         mEditText.setSelection(mEditText.getText().length());
         mEditText.requestFocus();
+        updateSendButton();
+    }
+
+    public void onNotificationUpdate() {
+        boolean sending = mProgressBar.getVisibility() == VISIBLE;
+
+        if (sending) {
+            // Update came in after we sent the reply, time to reset.
+            reset();
+        }
+    }
+
+    private void reset() {
+        mEditText.getText().clear();
+        mEditText.setEnabled(true);
+        mSendButton.setVisibility(VISIBLE);
+        mProgressBar.setVisibility(INVISIBLE);
+        updateSendButton();
+        onDefocus();
+    }
+
+    private void updateSendButton() {
+        mSendButton.setEnabled(mEditText.getText().length() != 0);
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        updateSendButton();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 9015a0e..beaa3ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -23,9 +23,11 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
 import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -49,6 +51,7 @@
     private final int mNotificatonTopPadding;
     private final HybridNotificationViewManager mHybridViewManager;
     private final float mCollapsedBottompadding;
+    private ViewInvertHelper mOverflowInvertHelper;
     private boolean mChildrenExpanded;
     private ExpandableNotificationRow mNotificationParent;
     private HybridNotificationView mGroupOverflowContainer;
@@ -87,7 +90,7 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int childCount = mChildren.size();
+        int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
         for (int i = 0; i < childCount; i++) {
             View child = mChildren.get(i);
             if (child.getVisibility() == View.GONE) {
@@ -115,7 +118,7 @@
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
         int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
         int height = mNotificationHeaderHeight + mNotificatonTopPadding;
-        int childCount = mChildren.size();
+        int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
         for (int i = 0; i < childCount; i++) {
             View child = mChildren.get(i);
             child.measure(widthMeasureSpec, newHeightSpec);
@@ -172,12 +175,17 @@
         if (hasOverflow) {
             mGroupOverflowContainer = mHybridViewManager.bindFromNotificationGroup(
                     mGroupOverflowContainer, mChildren, lastVisibleIndex + 1);
+            if (mOverflowInvertHelper == null) {
+                mOverflowInvertHelper= new ViewInvertHelper(mGroupOverflowContainer,
+                        NotificationPanelView.DOZE_ANIMATION_DURATION);
+            }
             if (mGroupOverFlowState == null) {
                 mGroupOverFlowState = new ViewState();
             }
         } else if (mGroupOverflowContainer != null) {
             removeView(mGroupOverflowContainer);
             mGroupOverflowContainer = null;
+            mOverflowInvertHelper = null;
             mGroupOverFlowState = null;
         }
     }
@@ -324,7 +332,7 @@
         if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
             return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
         }
-        if (mNotificationParent.isExpanded()) {
+        if (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp()) {
             return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
         }
         return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
@@ -387,16 +395,17 @@
             boolean withDelays, long baseDelay, long duration) {
         int childCount = mChildren.size();
         ViewState tmpState = new ViewState();
-        int notGoneIndex = 0;
-        for (int i = 0; i < childCount; i++) {
+        int delayIndex = 0;
+        int maxAllowChildCount = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+        for (int i = childCount - 1; i >= 0; i--) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
             int difference = Math.min(StackStateAnimator.DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN,
-                    notGoneIndex + 1);
+                    delayIndex);
             long delay = withDelays
                     ? difference * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN
                     : 0;
-            delay += baseDelay;
+            delay = (long) (delay * (mChildrenExpanded ? 1.0f : 0.5f) + baseDelay);
             stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
 
             // layout the divider
@@ -405,11 +414,13 @@
             tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
             tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
             stateAnimator.startViewAnimations(divider, tmpState, delay, duration);
-
-            notGoneIndex++;
+            if (i < maxAllowChildCount) {
+                delayIndex++;
+            }
         }
         if (mGroupOverflowContainer != null) {
-            stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState, -1, 0);
+            stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState,
+                    baseDelay, duration);
         }
     }
 
@@ -443,4 +454,10 @@
     public int getMinHeight() {
         return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
     }
+
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (mGroupOverflowContainer != null) {
+            mOverflowInvertHelper.setInverted(dark, fade, delay);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index ae6b729..2ce19a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2750,14 +2750,6 @@
         return max + getStackTranslation();
     }
 
-    /**
-     * @param qsMinHeight The minimum height of the quick settings including padding
-     *                    See {@link StackScrollAlgorithm#updateIsSmallScreen}.
-     */
-    public void updateIsSmallScreen(int qsMinHeight) {
-        mStackScrollAlgorithm.updateIsSmallScreen(mMaxLayoutHeight - qsMinHeight);
-    }
-
     public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
         this.mPhoneStatusBar = phoneStatusBar;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 953f287..59b446b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -422,6 +422,7 @@
             StackViewState childViewState = resultState.getViewStateForView(child);
             childViewState.location = StackViewState.LOCATION_UNKNOWN;
             int childHeight = getMaxAllowedChildHeight(child, ambientState);
+            int minHeight = child.getMinHeight();
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
                     + mPaddingBetweenElements;
@@ -450,17 +451,17 @@
 
                 // check if we are overlapping with the bottom stack
                 if (childViewState.yTranslation + childHeight + mPaddingBetweenElements
-                        >= bottomStackStart && !mIsExpansionChanging && i != 0 && mIsSmallScreen) {
+                        >= bottomStackStart && !mIsExpansionChanging && i != 0) {
                     // we just collapse this element slightly
                     int newSize = (int) Math.max(bottomStackStart - mPaddingBetweenElements -
-                            childViewState.yTranslation, child.getMinHeight());
+                            childViewState.yTranslation, minHeight);
                     childViewState.height = newSize;
                     updateStateForChildTransitioningInBottom(algorithmState, bottomStackStart,
                             child, childViewState.yTranslation, childViewState,
                             childHeight);
                 }
                 clampPositionToBottomStackStart(childViewState, childViewState.height,
-                        ambientState);
+                        minHeight, ambientState);
             } else if (nextYPosition >= bottomStackStart) {
                 // Case 2:
                 // We are in the bottom stack.
@@ -468,7 +469,7 @@
                     // According to the regular scroll view we are fully translated out of the
                     // bottom of the screen so we are fully in the bottom stack
                     updateStateForChildFullyInBottomStack(algorithmState,
-                            bottomStackStart, childViewState, childHeight, ambientState);
+                            bottomStackStart, childViewState, minHeight, ambientState);
                 } else {
                     // According to the regular scroll view we are currently translating out of /
                     // into the bottom of the screen
@@ -560,12 +561,13 @@
      * Clamp the yTranslation both up and down to valid positions.
      *
      * @param childViewState the view state of the child
-     * @param childHeight the height of this child
+     * @param minHeight the minimum height of this child
      */
-    private void clampYTranslation(StackViewState childViewState, int childHeight,
+    private void clampYTranslation(StackViewState childViewState, int minHeight,
             AmbientState ambientState) {
-        clampPositionToBottomStackStart(childViewState, childHeight, ambientState);
-        clampPositionToTopStackEnd(childViewState, childHeight);
+        clampPositionToBottomStackStart(childViewState, childViewState.height, minHeight,
+                ambientState);
+        clampPositionToTopStackEnd(childViewState, childViewState.height);
     }
 
     /**
@@ -574,12 +576,22 @@
      *
      * @param childViewState the view state of the child
      * @param childHeight the height of this child
+     * @param minHeight the minumum Height of the View
      */
     private void clampPositionToBottomStackStart(StackViewState childViewState,
-            int childHeight, AmbientState ambientState) {
-        childViewState.yTranslation = Math.min(childViewState.yTranslation,
-                ambientState.getInnerHeight() - mBottomStackPeekSize - mCollapseSecondCardPadding
-                        - childHeight);
+            int childHeight, int minHeight, AmbientState ambientState) {
+
+        int bottomStackStart = ambientState.getInnerHeight()
+                - mBottomStackPeekSize - mCollapseSecondCardPadding;
+        int childStart = bottomStackStart - childHeight;
+        if (childStart < childViewState.yTranslation) {
+            float newHeight = bottomStackStart - childViewState.yTranslation;
+            if (newHeight < minHeight) {
+                newHeight = minHeight;
+                childViewState.yTranslation = bottomStackStart - minHeight;
+            }
+            childViewState.height = (int) newHeight;
+        }
     }
 
     /**
@@ -624,7 +636,7 @@
         float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
         algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
         int newHeight = childHeight;
-        if (childHeight > child.getMinHeight() && mIsSmallScreen) {
+        if (childHeight > child.getMinHeight()) {
             newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
                     mPaddingBetweenElements - currentYPosition, childHeight),
                     child.getMinHeight());
@@ -640,7 +652,7 @@
 
     private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
             float transitioningPositionStart, StackViewState childViewState,
-            int childHeight, AmbientState ambientState) {
+            int minHeight, AmbientState ambientState) {
         float currentYPosition;
         algorithmState.itemsInBottomStack += 1.0f;
         if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
@@ -660,8 +672,9 @@
             childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
             currentYPosition = ambientState.getInnerHeight();
         }
-        childViewState.yTranslation = currentYPosition - childHeight;
-        clampPositionToTopStackEnd(childViewState, childHeight);
+        childViewState.height = minHeight;
+        childViewState.yTranslation = currentYPosition - minHeight;
+        clampPositionToTopStackEnd(childViewState, minHeight);
     }
 
     private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
@@ -835,19 +848,6 @@
         }
     }
 
-    /**
-     * Update whether the device is very small, i.e. Notifications can be in both the top and the
-     * bottom stack at the same time
-     *
-     * @param panelHeight The normal height of the panel when it's open
-     */
-    public void updateIsSmallScreen(int panelHeight) {
-        mIsSmallScreen = panelHeight <
-                mCollapsedSize  /* top stack */
-                + mBottomStackSlowDownLength + mBottomStackPeekSize /* bottom stack */
-                + mMaxNotificationHeight; /* max notification height */
-    }
-
     public void onExpansionStarted(StackScrollState currentState) {
         mIsExpansionChanging = true;
         mExpandedOnStart = mIsExpanded;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 39a2986..44b41c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -135,7 +135,7 @@
     }
 
     @Override
-    public void animateExpandSettingsPanel() {
+    public void animateExpandSettingsPanel(String subPanel) {
     }
 
     @Override
@@ -175,7 +175,7 @@
     }
 
     @Override
-    protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldInterrupt,
+    protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldPeek,
             boolean alertAgain) {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index da19b06..9d4ec10 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -128,6 +128,7 @@
     private boolean mPendingRecheckAll;
     private long mCollapseTime;
     private boolean mHovering = false;
+    private int mLastActiveStream;
 
     public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
             ZenModeController zenModeController, Callback callback) {
@@ -283,10 +284,14 @@
             @Override
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                final boolean moved = oldLeft != left || oldTop != top;
+                final boolean moved = mLastActiveStream != mActiveStream ||
+                        oldLeft != left || oldTop != top;
                 if (D.BUG) Log.d(TAG, "onLayoutChange moved=" + moved
                         + " old=" + new Rect(oldLeft, oldTop, oldRight, oldBottom).toShortString()
-                        + " new=" + new Rect(left,top,right,bottom).toShortString());
+                        + "," + mLastActiveStream
+                        + " new=" + new Rect(left,top,right,bottom).toShortString()
+                        + "," + mActiveStream);
+                mLastActiveStream = mActiveStream;
                 if (moved) {
                     for (int i = 0; i < mDialogContentView.getChildCount(); i++) {
                         final View c = mDialogContentView.getChildAt(i);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 11fdbb5..8cf25b3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3987,6 +3987,9 @@
         private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
 
+        private final Uri mDisplayColorMatrixUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+
         private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
 
@@ -4017,6 +4020,8 @@
             contentResolver.registerContentObserver(
                     mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
+                    mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
         }
 
@@ -4066,6 +4071,8 @@
                     if (readDisplayColorAdjustmentSettingsLocked(userState)) {
                         updateDisplayColorAdjustmentSettingsLocked(userState);
                     }
+                } else if (mDisplayColorMatrixUri.equals(uri)) {
+                    updateDisplayColorAdjustmentSettingsLocked(userState);
                 } else if (mHighTextContrastUri.equals(uri)) {
                     if (readHighTextContrastEnabledSettingLocked(userState)) {
                         onUserStateChangedLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index d0b5898..1a7de25 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -107,9 +107,24 @@
             setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
         }
 
+        String matrix = Settings.Secure.getStringForUser(cr,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, userId);
+        if (matrix != null) {
+            colorMatrix = multiply(colorMatrix, getMatrix(matrix));
+        }
+
         setColorTransform(colorMatrix);
     }
 
+    private static float[] getMatrix(String matrix) {
+        String[] strValues = matrix.split(",");
+        float[] values = new float[strValues.length];
+        for (int i = 0; i < values.length; i++) {
+            values[i] = Float.parseFloat(strValues[i]);
+        }
+        return values;
+    }
+
     private static float[] multiply(float[] matrix, float[] other) {
         if (matrix == null) {
             return other;
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 960fb4b..5f57a76 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1233,14 +1233,6 @@
                 }
             }
 
-            // direct-callback alarms must be wakeup alarms (otherwise they should just be
-            // posting work to a Handler)
-            if (directReceiver != null) {
-                if (type != RTC_WAKEUP && type != ELAPSED_REALTIME_WAKEUP) {
-                    throw new IllegalArgumentException("Only wakeup alarms can use AlarmReceivers");
-                }
-            }
-
             if (workSource != null) {
                 getContext().enforcePermission(
                         android.Manifest.permission.UPDATE_DEVICE_STATS,
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ede92fb..353b404 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -788,6 +788,9 @@
 
     @Override
     public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
+        if (callback == null) {
+            return;
+        }
         synchronized (this) {
             op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
             Callback cb = mModeWatchers.get(callback.asBinder());
@@ -816,6 +819,9 @@
 
     @Override
     public void stopWatchingMode(IAppOpsCallback callback) {
+        if (callback == null) {
+            return;
+        }
         synchronized (this) {
             Callback cb = mModeWatchers.remove(callback.asBinder());
             if (cb != null) {
@@ -1170,6 +1176,9 @@
                             if ("media".equals(packageName)) {
                                 pkgUid = Process.MEDIA_UID;
                                 isPrivileged = false;
+                            } else if ("audioserver".equals(packageName)) {
+                                pkgUid = Process.AUDIOSERVER_UID;
+                                isPrivileged = false;
                             }
                         }
                     } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c712a56..65a27c8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -34,6 +34,7 @@
 
 import android.annotation.Nullable;
 import android.app.AlarmManager;
+import android.app.BroadcastOptions;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -72,6 +73,7 @@
 import android.net.UidRange;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -253,11 +255,6 @@
     private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
 
     /**
-     * used internally to send a sticky broadcast delayed.
-     */
-    private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11;
-
-    /**
      * PAC manager has received new port.
      */
     private static final int EVENT_PROXY_HAS_CHANGED = 16;
@@ -1529,6 +1526,7 @@
                 log("sendStickyBroadcast: action=" + intent.getAction());
             }
 
+            Bundle options = null;
             final long ident = Binder.clearCallingIdentity();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                 final NetworkInfo ni = intent.getParcelableExtra(
@@ -1536,6 +1534,10 @@
                 if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) {
                     intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                } else {
+                    BroadcastOptions opts = BroadcastOptions.makeBasic();
+                    opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
+                    options = opts.toBundle();
                 }
                 final IBatteryStats bs = BatteryStatsService.getService();
                 try {
@@ -1546,7 +1548,7 @@
                 }
             }
             try {
-                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -2508,11 +2510,6 @@
                     handleDeprecatedGlobalHttpProxy();
                     break;
                 }
-                case EVENT_SEND_STICKY_BROADCAST_INTENT: {
-                    Intent intent = (Intent)msg.obj;
-                    sendStickyBroadcast(intent);
-                    break;
-                }
                 case EVENT_PROXY_HAS_CHANGED: {
                     handleApplyDefaultProxy((ProxyInfo)msg.obj);
                     break;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 45c1ed2..04abcca 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -166,6 +166,7 @@
     static final int MSG_SET_ACTIVE = 3020;
     static final int MSG_SET_INTERACTIVE = 3030;
     static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 3040;
+    static final int MSG_SWITCH_IME = 3050;
 
     static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
 
@@ -2851,6 +2852,9 @@
             case MSG_SET_INTERACTIVE:
                 handleSetInteractive(msg.arg1 != 0);
                 return true;
+            case MSG_SWITCH_IME:
+                handleSwitchInputMethod(msg.arg1 != 0);
+                return true;
             case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
                 final int sequenceNumber = msg.arg1;
                 final ClientState clientState = (ClientState)msg.obj;
@@ -2887,6 +2891,18 @@
         }
     }
 
+    private void handleSwitchInputMethod(final boolean forwardDirection) {
+        synchronized (mMethodMap) {
+            // TODO: Support forwardDirection.
+            final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
+                    false, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+            if (nextSubtype == null) {
+                return;
+            }
+            setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+        }
+    }
+
     private boolean chooseNewDefaultIMELocked() {
         final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
                 mSettings.getEnabledInputMethodListLocked());
@@ -3027,7 +3043,7 @@
 
             final List<ImeSubtypeListItem> imList =
                     mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
-                            true /* showSubtypes */, showAuxSubtypes, isScreenLocked);
+                            showAuxSubtypes, isScreenLocked);
 
             if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
                 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
@@ -3536,6 +3552,7 @@
         private static final String ATTR_LABEL = "label";
         private static final String ATTR_ICON = "icon";
         private static final String ATTR_IME_SUBTYPE_LOCALE = "imeSubtypeLocale";
+        private static final String ATTR_IME_SUBTYPE_LANGUAGE_TAG = "languageTag";
         private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode";
         private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue";
         private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
@@ -3629,6 +3646,8 @@
                         out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
                         out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
                         out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
+                        out.attribute(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG,
+                                subtype.getLanguageTag());
                         out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
                         out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
                         out.attribute(null, ATTR_IS_AUXILIARY,
@@ -3690,6 +3709,8 @@
                                 parser.getAttributeValue(null, ATTR_LABEL));
                         final String imeSubtypeLocale =
                                 parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
+                        final String languageTag =
+                                parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG);
                         final String imeSubtypeMode =
                                 parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
                         final String imeSubtypeExtraValue =
@@ -3700,6 +3721,7 @@
                                 .setSubtypeNameResId(label)
                                 .setSubtypeIconResId(icon)
                                 .setSubtypeLocale(imeSubtypeLocale)
+                                .setLanguageTag(languageTag)
                                 .setSubtypeMode(imeSubtypeMode)
                                 .setSubtypeExtraValue(imeSubtypeExtraValue)
                                 .setIsAuxiliary(isAuxiliary)
@@ -3728,6 +3750,13 @@
             mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_INTERACTIVE,
                     interactive ? 1 : 0, 0));
         }
+
+        @Override
+        public void switchInputMethod(boolean forwardDirection) {
+            // Do everything in handler so as not to block the caller.
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SWITCH_IME,
+                    forwardDirection ? 1 : 0, 0));
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 033a4b8..1a21f5c 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -356,6 +356,10 @@
             }
         }
 
+        if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
+            key = Settings.Secure.LOCK_PATTERN_ENABLED;
+        }
+
         return mStorage.readKeyValue(key, defaultValue, userId);
     }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 502d61a..ca5212a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2449,7 +2449,7 @@
             if (sessionBundle != null) {
                 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
                 if (TextUtils.isEmpty(accountType)
-                        && !mAccountType.equalsIgnoreCase(mAccountType)) {
+                        || !mAccountType.equalsIgnoreCase(accountType)) {
                     Log.w(TAG, "Account type in session bundle doesn't match request.");
                 }
                 // Add accountType info to session bundle. This will
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e4a6f3c..90a5d3f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -490,6 +490,8 @@
 
     // Used to indicate that a task is removed it should also be removed from recents.
     private static final boolean REMOVE_FROM_RECENTS = true;
+    // Used to indicate that an app transition should be animated.
+    private static final boolean ANIMATE = true;
 
     private static native int nativeMigrateToBoost();
     private static native int nativeMigrateFromBoost();
@@ -1432,6 +1434,7 @@
     static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
     static final int IDLE_UIDS_MSG = 60;
     static final int SYSTEM_USER_UNLOCK_MSG = 61;
+    static final int LOG_STACK_STATE = 62;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2141,6 +2144,11 @@
             case IDLE_UIDS_MSG: {
                 idleUids();
             } break;
+            case LOG_STACK_STATE: {
+                synchronized (ActivityManagerService.this) {
+                    mStackSupervisor.logStackState();
+                }
+            } break;
             }
         }
     };
@@ -3484,27 +3492,29 @@
                 Watchdog.getInstance().processStarted(app.processName, startResult.pid);
             }
 
-            checkTime(startTime, "startProcess: building log message");
-            StringBuilder buf = mStringBuilder;
-            buf.setLength(0);
-            buf.append("Start proc ");
-            buf.append(startResult.pid);
-            buf.append(':');
-            buf.append(app.processName);
-            buf.append('/');
-            UserHandle.formatUid(buf, uid);
-            if (!isActivityProcess) {
-                buf.append(" [");
-                buf.append(entryPoint);
-                buf.append("]");
+            if (DEBUG_PROCESSES) {
+                checkTime(startTime, "startProcess: building log message");
+                StringBuilder buf = mStringBuilder;
+                buf.setLength(0);
+                buf.append("Start proc ");
+                buf.append(startResult.pid);
+                buf.append(':');
+                buf.append(app.processName);
+                buf.append('/');
+                UserHandle.formatUid(buf, uid);
+                if (!isActivityProcess) {
+                    buf.append(" [");
+                    buf.append(entryPoint);
+                    buf.append("]");
+                }
+                buf.append(" for ");
+                buf.append(hostingType);
+                if (hostingNameStr != null) {
+                    buf.append(" ");
+                    buf.append(hostingNameStr);
+                }
+                Slog.i(TAG, buf.toString());
             }
-            buf.append(" for ");
-            buf.append(hostingType);
-            if (hostingNameStr != null) {
-                buf.append(" ");
-                buf.append(hostingNameStr);
-            }
-            Slog.i(TAG, buf.toString());
             app.setPid(startResult.pid);
             app.usingWrapper = startResult.usingWrapper;
             app.removed = false;
@@ -4331,7 +4341,7 @@
                 if (task.stack.mStackId != launchStackId) {
                     mStackSupervisor.moveTaskToStackLocked(
                             taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
-                            true /* animate */);
+                            ANIMATE);
                 }
             }
 
@@ -5386,7 +5396,7 @@
                     return;
                 }
                 killPackageProcessesLocked(packageName, appId, userId,
-                        ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+                        ProcessList.SERVICE_ADJ, false, true, true, false, true, "kill background");
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -5687,7 +5697,7 @@
 
     private final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
-            boolean doit, boolean evenPersistent, String reason) {
+            boolean doit, boolean evenPersistent, boolean killPackageApp, String reason) {
         ArrayList<ProcessRecord> procs = new ArrayList<>();
 
         // Remove all processes this package may have touched: all with the
@@ -5736,7 +5746,7 @@
                     if (userId != UserHandle.USER_ALL && app.userId != userId) {
                         continue;
                     }
-                    if (!app.pkgList.containsKey(packageName) && !isDep) {
+                    if ((!killPackageApp || !app.pkgList.containsKey(packageName)) && !isDep) {
                         continue;
                     }
                 }
@@ -5902,7 +5912,7 @@
         }
 
         boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
-                ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
+                ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent, true,
                 packageName == null ? ("stop user " + userId) : ("stop " + packageName));
 
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
@@ -9312,7 +9322,7 @@
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r
                         + " to stackId=" + stackId);
                 mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS,
-                        "moveActivityToStack", true /* animate */);
+                        "moveActivityToStack", ANIMATE);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -9333,7 +9343,7 @@
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
                         + " to stackId=" + stackId + " toTop=" + toTop);
                 mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS,
-                        "moveTaskToStack", true /* animate */);
+                        "moveTaskToStack", ANIMATE);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -10898,6 +10908,7 @@
 
     /** Notifies all listeners when the task stack has changed. */
     void notifyTaskStackChangedLocked() {
+        mHandler.sendEmptyMessage(LOG_STACK_STATE);
         mHandler.removeMessages(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
         Message nmsg = mHandler.obtainMessage(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
         mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
@@ -11768,13 +11779,11 @@
 
         boolean killed = false;
         synchronized (mPidsSelfLocked) {
-            int[] types = new int[pids.length];
             int worstType = 0;
             for (int i=0; i<pids.length; i++) {
                 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
                 if (proc != null) {
                     int type = proc.setAdj;
-                    types[i] = type;
                     if (type > worstType) {
                         worstType = type;
                     }
@@ -11817,7 +11826,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 killPackageProcessesLocked(null, appId, userId,
-                        ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true,
+                        ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true, true,
                         reason != null ? reason : "kill uid");
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -17777,20 +17786,20 @@
     }
 
     @Override
-    public void removeStack(int stackId) {
+    public void moveTasksToFullscreenStack(int fromStackId) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "detahStack()");
-        if (stackId == HOME_STACK_ID) {
-            throw new IllegalArgumentException("Removing home stack is not allowed.");
+                "moveTasksToFullscreenStack()");
+        if (fromStackId == HOME_STACK_ID) {
+            throw new IllegalArgumentException("You can't move tasks from the home stack.");
         }
         synchronized (this) {
-            long origId = Binder.clearCallingIdentity();
-            ActivityStack stack = mStackSupervisor.getStack(stackId);
+            final long origId = Binder.clearCallingIdentity();
+            final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
             if (stack != null) {
-                ArrayList<TaskRecord> tasks = stack.getAllTasks();
+                final ArrayList<TaskRecord> tasks = stack.getAllTasks();
                 for (int i = tasks.size() - 1; i >= 0; i--) {
-                    removeTaskByIdLocked(tasks.get(i).taskId, false /* killProcess */,
-                            !REMOVE_FROM_RECENTS);
+                    mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
+                            FULLSCREEN_WORKSPACE_STACK_ID, 0);
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -19748,7 +19757,7 @@
                         } else {
                             numEmpty++;
                             if (numEmpty > emptyProcessLimit) {
-                                app.kill("empty #" + numEmpty, true);
+                                app.kill("empty #" + numEmpty, DEBUG_PROCESSES);
                             }
                         }
                         break;
@@ -20775,4 +20784,35 @@
             }
         }
     }
+
+    /**
+     * Kill processes for the user with id userId and that depend on the package named packageName
+     */
+    @Override
+    public void killPackageDependents(String packageName, int userId) {
+        enforceCallingPermission(android.Manifest.permission.KILL_UID, "killPackageDependents()");
+        if (packageName == null) {
+            throw new NullPointerException("Cannot kill the dependents of a package without its name.");
+        }
+
+        long callingId = Binder.clearCallingIdentity();
+        IPackageManager pm = AppGlobals.getPackageManager();
+        int pkgUid = -1;
+        try {
+            pkgUid = pm.getPackageUid(packageName, userId);
+        } catch (RemoteException e) {
+        }
+        if (pkgUid == -1) {
+            throw new IllegalArgumentException("Cannot kill dependents of non-existing package " + packageName);
+        }
+        try {
+            synchronized(this) {
+                killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), userId,
+                        ProcessList.FOREGROUND_APP_ADJ, false, true, true, false, false,
+                        "dep: " + packageName);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
new file mode 100644
index 0000000..64f423c
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -0,0 +1,72 @@
+package com.android.server.am;
+
+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 android.app.ActivityManager.StackId;
+import android.content.Context;
+import android.os.SystemClock;
+
+import com.android.internal.logging.MetricsLogger;
+
+/**
+ * Handles logging into Tron.
+ */
+class ActivityMetricsLogger {
+    // Window modes we are interested in logging. If we ever introduce a new type, we need to add
+    // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
+    private static final int WINDOW_STATE_STANDARD = 0;
+    private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
+    private static final int WINDOW_STATE_FREEFORM = 2;
+    private static final int WINDOW_STATE_INVALID = -1;
+
+    // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
+    // time we log.
+    private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
+            "tron_varz_window_time_0", "tron_varz_window_time_1", "tron_varz_window_time_2"};
+
+    private int mWindowState = WINDOW_STATE_STANDARD;
+    private long mLastLogTimeSecs;
+    private final ActivityStackSupervisor mSupervisor;
+    private final Context mContext;
+
+    ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
+        mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
+        mSupervisor = supervisor;
+        mContext = context;
+    }
+
+    void logWindowState() {
+        final long now = SystemClock.elapsedRealtime() / 1000;
+        if (mWindowState != WINDOW_STATE_INVALID) {
+            // We log even if the window state hasn't changed, because the user might remain in
+            // home/fullscreen move forever and we would like to track this kind of behavior
+            // too.
+            MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
+                    (int) (now - mLastLogTimeSecs));
+        }
+        mLastLogTimeSecs = now;
+
+        mWindowState = WINDOW_STATE_INVALID;
+        ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
+        if (stack != null && stack.isStackVisibleLocked()) {
+            mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
+        }
+        if (mWindowState == WINDOW_STATE_INVALID) {
+            stack = mSupervisor.getFocusedStack();
+            if (stack.mStackId == HOME_STACK_ID
+                    || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+                mWindowState = WINDOW_STATE_STANDARD;
+            } else if (stack.mStackId == DOCKED_STACK_ID) {
+                throw new IllegalStateException("Docked stack shouldn't be the focused stack, "
+                        + "because it reported not being visible.");
+            } else if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                mWindowState = WINDOW_STATE_FREEFORM;
+            } else if (StackId.isStaticStack(stack.mStackId)) {
+                throw new IllegalStateException("Unknown stack=" + stack);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b052d17..ffa6a4d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -74,6 +74,7 @@
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 
@@ -733,7 +734,7 @@
                 "Launch completed; removing icicle of " + r.icicle);
     }
 
-    private void addRecentActivityLocked(ActivityRecord r) {
+    void addRecentActivityLocked(ActivityRecord r) {
         if (r != null) {
             mRecentTasks.addLocked(r.task);
             r.task.touchActiveTime();
@@ -1333,7 +1334,7 @@
     }
 
     /** Returns true if the stack is considered visible. */
-    private boolean isStackVisibleLocked() {
+    boolean isStackVisibleLocked() {
         if (!isAttached()) {
             return false;
         }
@@ -1358,6 +1359,13 @@
         final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
         final int focusedStackId = focusedStack.mStackId;
 
+        if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID
+                && hasVisibleBehindActivity() && focusedStackId == HOME_STACK_ID) {
+            // The fullscreen stack should be visible if it has a visible behind activity behind
+            // the home stack that will be translucent.
+            return true;
+        }
+
         if (mStackId == DOCKED_STACK_ID) {
             // Docked stack is always visible, except in the case where the home activity
             // is the top running activity in the focused home stack.
@@ -2312,8 +2320,8 @@
         updateTaskMovement(task, true);
     }
 
-    final void startActivityLocked(ActivityRecord r, boolean newTask,
-            boolean doResume, boolean keepCurTransition, ActivityOptions options) {
+    final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
+            ActivityOptions options) {
         TaskRecord rTask = r.task;
         final int taskId = rTask.taskId;
         // mLaunchTaskBehind tasks get placed at the back of the task stack.
@@ -2459,12 +2467,6 @@
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
-
-        if (doResume) {
-            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
-        } else {
-            addRecentActivityLocked(r);
-        }
     }
 
     final void validateAppTokensLocked() {
@@ -3990,6 +3992,20 @@
 
         if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
 
+        if (mStackId == HOME_STACK_ID && topTask().isHomeTask()) {
+            // For the case where we are moving the home task back and there is an activity visible
+            // behind it on the fullscreen stack, we want to move the focus to the visible behind
+            // activity to maintain order with what the user is seeing.
+            final ActivityStack fullscreenStack =
+                    mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
+            if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
+                final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
+                mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
+                mStackSupervisor.resumeTopActivitiesLocked(fullscreenStack, null, null);
+                return true;
+            }
+        }
+
         boolean prevIsHome = false;
 
         // If true, we should resume the home activity next if the task we are moving to the
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f4ba19f..e1bc580 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -29,12 +29,12 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
@@ -76,7 +76,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
@@ -107,7 +106,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
-import android.os.storage.StorageManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -123,13 +121,11 @@
 import android.view.DisplayInfo;
 import android.view.InputEvent;
 import android.view.Surface;
-import android.widget.Toast;
 
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.TransferPipe;
-import com.android.internal.R;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.LockPatternUtils;
@@ -374,6 +370,8 @@
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
 
+    private final ActivityMetricsLogger mActivityMetricsLogger;
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -410,6 +408,7 @@
         mService = service;
         mRecentTasks = recentTasks;
         mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
+        mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
     }
 
     /**
@@ -1549,7 +1548,7 @@
             // to ensure that it is safe to do so.  If the upcoming activity will also
             // be part of the voice session, we can only launch it if it has explicitly
             // said it supports the VOICE category, or it is a part of the calling app.
-            if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+            if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
                     && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
                 try {
                     intent.addCategory(Intent.CATEGORY_VOICE);
@@ -1596,63 +1595,9 @@
             return err;
         }
 
-        boolean abort = false;
-
-        final int startAnyPerm = mService.checkPermission(
-                START_ANY_ACTIVITY, callingPid, callingUid);
-
-        if (startAnyPerm != PERMISSION_GRANTED) {
-            final int componentRestriction = getComponentRestrictionForCallingPackage(
-                    aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
-            final int actionRestriction = getActionRestrictionForCallingPackage(
-                    intent.getAction(), callingPackage, callingPid, callingUid);
-
-            if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
-                    || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
-                if (resultRecord != null) {
-                    resultStack.sendActivityResultLocked(-1,
-                            resultRecord, resultWho, requestCode,
-                            Activity.RESULT_CANCELED, null);
-                }
-                String msg;
-                if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
-                    msg = "Permission Denial: starting " + intent.toString()
-                            + " from " + callerApp + " (pid=" + callingPid
-                            + ", uid=" + callingUid + ")" + " with revoked permission "
-                            + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
-                } else if (!aInfo.exported) {
-                    msg = "Permission Denial: starting " + intent.toString()
-                            + " from " + callerApp + " (pid=" + callingPid
-                            + ", uid=" + callingUid + ")"
-                            + " not exported from uid " + aInfo.applicationInfo.uid;
-                } else {
-                    msg = "Permission Denial: starting " + intent.toString()
-                            + " from " + callerApp + " (pid=" + callingPid
-                            + ", uid=" + callingUid + ")"
-                            + " requires " + aInfo.permission;
-                }
-                Slog.w(TAG, msg);
-                throw new SecurityException(msg);
-            }
-
-            if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) {
-                String message = "Appop Denial: starting " + intent.toString()
-                        + " from " + callerApp + " (pid=" + callingPid
-                        + ", uid=" + callingUid + ")"
-                        + " requires " + AppOpsManager.permissionToOp(
-                                ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()));
-                Slog.w(TAG, message);
-                abort = true;
-            } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) {
-                String message = "Appop Denial: starting " + intent.toString()
-                        + " from " + callerApp + " (pid=" + callingPid
-                        + ", uid=" + callingUid + ")"
-                        + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission);
-                Slog.w(TAG, message);
-                abort = true;
-            }
-        }
-
+        boolean abort = !checkStartAnyActivityPermission(intent, aInfo, resultWho, requestCode,
+                callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
+                resultRecord, resultStack);
         abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                 callingPid, resolvedType, aInfo.applicationInfo);
 
@@ -1681,21 +1626,23 @@
                     PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                             | PendingIntent.FLAG_IMMUTABLE, null);
             int flags = intent.getFlags();
-            intent = km.createConfirmDeviceCredentialIntent(null, null);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
-            intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
-            intent.putExtra(Intent.EXTRA_USER_ID, userId);
-            intent.setFlags(flags);
+            Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, user.id);
+            if (newIntent != null) {
+                intent = newIntent;
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
+                intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
+                intent.setFlags(flags);
 
-            resolvedType = null;
-            callingUid = realCallingUid;
-            callingPid = realCallingPid;
+                resolvedType = null;
+                callingUid = realCallingUid;
+                callingPid = realCallingPid;
 
-            UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
-            aInfo = resolveActivity(intent, null, PackageManager.MATCH_DEFAULT_ONLY
-                    | ActivityManagerService.STOCK_PM_FLAGS, null, parent.id);
+                UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
+                aInfo = resolveActivity(intent, null, PackageManager.MATCH_DEFAULT_ONLY
+                        | ActivityManagerService.STOCK_PM_FLAGS, null, parent.id);
+            }
         }
 
         if (abort) {
@@ -1801,6 +1748,66 @@
         return err;
     }
 
+    private boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
+            String resultWho, int requestCode, int callingPid, int callingUid,
+            String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
+            ActivityRecord resultRecord, ActivityStack resultStack) {
+        final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
+                callingUid);
+        if (startAnyPerm ==  PERMISSION_GRANTED) {
+            return true;
+        }
+        final int componentRestriction = getComponentRestrictionForCallingPackage(
+                aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
+        final int actionRestriction = getActionRestrictionForCallingPackage(
+                intent.getAction(), callingPackage, callingPid, callingUid);
+        if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
+                || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
+            if (resultRecord != null) {
+                resultStack.sendActivityResultLocked(-1,
+                        resultRecord, resultWho, requestCode,
+                        Activity.RESULT_CANCELED, null);
+            }
+            final String msg;
+            if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")" + " with revoked permission "
+                        + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
+            } else if (!aInfo.exported) {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " not exported from uid " + aInfo.applicationInfo.uid;
+            } else {
+                msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ")"
+                        + " requires " + aInfo.permission;
+            }
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) {
+            final String message = "Appop Denial: starting " + intent.toString()
+                    + " from " + callerApp + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ")"
+                    + " requires " + AppOpsManager.permissionToOp(
+                            ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()));
+            Slog.w(TAG, message);
+            return false;
+        } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) {
+            final String message = "Appop Denial: starting " + intent.toString()
+                    + " from " + callerApp + " (pid=" + callingPid
+                    + ", uid=" + callingUid + ")"
+                    + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission);
+            Slog.w(TAG, message);
+            return false;
+        }
+        return true;
+    }
+
     private UserInfo getUserInfo(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -1879,7 +1886,7 @@
         return ACTIVITY_RESTRICTION_NONE;
     }
 
-    ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds) {
+    private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds) {
         final TaskRecord task = r.task;
 
         if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
@@ -1994,7 +2001,7 @@
             Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
                     "\"singleInstance\" or \"singleTask\"");
             launchFlags &=
-                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
         } else {
             switch (r.info.documentLaunchMode) {
                 case ActivityInfo.DOCUMENT_LAUNCH_NONE:
@@ -2006,7 +2013,7 @@
                     launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                     break;
                 case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
-                    launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+                    launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
                     break;
             }
         }
@@ -2015,7 +2022,7 @@
                 && !launchSingleTask && !launchSingleInstance
                 && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
 
-        if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
+        if (r.resultTo != null && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
                 && r.resultTo.task.stack != null) {
             // For whatever reason this activity is being launched into a new
             // task...  yet the caller has requested a result back.  Well, that
@@ -2030,15 +2037,15 @@
         }
 
         if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
-            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+            launchFlags |= FLAG_ACTIVITY_NEW_TASK;
         }
 
         // If we are actually going to launch in to a new task, there are some cases where
         // we further want to do multiple task.
-        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+        if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
             if (launchTaskBehind
                     || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
-                launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+                launchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
             }
         }
 
@@ -2107,8 +2114,8 @@
             // If task is empty, then adopt the interesting intent launch flags in to the
             // activity being started.
             if (root == null) {
-                final int flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK
+                        | FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
                         | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
                 launchFlags = (launchFlags&~flagsOfInterest)
                         | (baseIntent.getFlags()&flagsOfInterest);
@@ -2119,7 +2126,7 @@
             // If the task is not empty and the caller is asking to start it as the root
             // of a new task, then we don't actually want to start this on the task.  We
             // will bring the task to the front, and possibly give it a new intent.
-            } else if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+            } else if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                 addingToTask = false;
 
             } else {
@@ -2143,20 +2150,20 @@
             if (sourceRecord == null) {
                 // This activity is not being started from another...  in this
                 // case we -always- start a new task.
-                if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
+                if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
                     Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                             "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
-                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+                    launchFlags |= FLAG_ACTIVITY_NEW_TASK;
                 }
             } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                 // The original activity who is starting us is running as a single
                 // instance...  this new activity it is starting must go on its
                 // own task.
-                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+                launchFlags |= FLAG_ACTIVITY_NEW_TASK;
             } else if (launchSingleInstance || launchSingleTask) {
                 // The activity being started is a single instance...  it always
                 // gets launched into its own task.
-                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+                launchFlags |= FLAG_ACTIVITY_NEW_TASK;
             }
         }
 
@@ -2170,10 +2177,10 @@
                 // so we don't want to blindly throw it in to that task.  Instead we will take
                 // the NEW_TASK flow and try to find a task for it. But save the task information
                 // so it can be used when creating the new task.
-                if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+                if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
                     Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                             + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
-                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+                    launchFlags |= FLAG_ACTIVITY_NEW_TASK;
                     newTaskInfo = sourceRecord.info;
                     newTaskIntent = sourceRecord.task.intent;
                 }
@@ -2192,216 +2199,192 @@
         intent.setFlags(launchFlags);
         final boolean noAnimation = (launchFlags & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0;
 
-        // We may want to try to place the new activity in to an existing task.  We always
-        // do this if the target activity is singleTask or singleInstance; we will also do
-        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
-        // us to still place it in a new task: multi task, always doc mode, or being asked to
-        // launch this as a new task behind the current one.
-        if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
-                || launchSingleInstance || launchSingleTask) {
-            // If bring to front is requested, and no result is requested and we have not
-            // been given an explicit task to launch in to, and
-            // we can find a task that was started with this same
-            // component, then instead of launching bring that one to the front.
-            if (inTask == null && r.resultTo == null) {
-                // See if there is a task to bring to the front.  If this is
-                // a SINGLE_INSTANCE activity, there can be one and only one
-                // instance of it in the history, and it is always in its own
-                // unique task, so we do a special search.
-                ActivityRecord intentActivity = !launchSingleInstance ?
-                        findTaskLocked(r) : findActivityLocked(intent, r.info);
-                if (intentActivity != null) {
-                    // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
-                    // but still needs to be a lock task mode violation since the task gets
-                    // cleared out and the device would otherwise leave the locked task.
-                    if (isLockTaskModeViolation(intentActivity.task,
-                            (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
-                        showLockTaskToast();
-                        Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
-                        return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+        ActivityRecord intentActivity = getReusableIntentActivity(r, inTask, intent,
+                launchSingleInstance, launchSingleTask, launchFlags);
+        if (intentActivity != null) {
+            // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
+            // but still needs to be a lock task mode violation since the task gets
+            // cleared out and the device would otherwise leave the locked task.
+            if (isLockTaskModeViolation(intentActivity.task,
+                    (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
+                showLockTaskToast();
+                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
+                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+            if (r.task == null) {
+                r.task = intentActivity.task;
+            }
+            if (intentActivity.task.intent == null) {
+                // This task was started because of movement of the activity based on affinity...
+                // Now that we are actually launching it, we can assign the base intent.
+                intentActivity.task.setIntent(r);
+            }
+            targetStack = intentActivity.task.stack;
+            targetStack.mLastPausedActivity = null;
+            // If the target task is not in the front, then we need
+            // to bring it to the front...  except...  well, with
+            // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
+            // to have the same behavior as if a new instance was
+            // being started, which means not bringing it to the front
+            // if the caller is not itself in the front.
+            final ActivityStack focusStack = getFocusedStack();
+            ActivityRecord curTop = (focusStack == null)
+                    ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
+            boolean movedToFront = false;
+            if (curTop != null && (curTop.task != intentActivity.task ||
+                    curTop.task != focusStack.topTask())) {
+                r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+                if (sourceRecord == null || (sourceStack.topActivity() != null &&
+                        sourceStack.topActivity().task == sourceRecord.task)) {
+                    // We really do want to push this one into the user's face, right now.
+                    if (launchTaskBehind && sourceRecord != null) {
+                        intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                     }
-                    if (r.task == null) {
-                        r.task = intentActivity.task;
+                    movedHome = true;
+                    targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
+                            options, r.appTimeTracker, "bringingFoundTaskToFront");
+                    movedToFront = true;
+                    if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+                        // Caller wants to appear on home activity.
+                        intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                     }
-                    if (intentActivity.task.intent == null) {
-                        // This task was started because of movement of
-                        // the activity based on affinity...  now that we
-                        // are actually launching it, we can assign the
-                        // base intent.
-                        intentActivity.task.setIntent(r);
-                    }
-                    targetStack = intentActivity.task.stack;
-                    targetStack.mLastPausedActivity = null;
-                    // If the target task is not in the front, then we need
-                    // to bring it to the front...  except...  well, with
-                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
-                    // to have the same behavior as if a new instance was
-                    // being started, which means not bringing it to the front
-                    // if the caller is not itself in the front.
-                    final ActivityStack focusStack = getFocusedStack();
-                    ActivityRecord curTop = (focusStack == null)
-                            ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
-                    boolean movedToFront = false;
-                    if (curTop != null && (curTop.task != intentActivity.task ||
-                            curTop.task != focusStack.topTask())) {
-                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
-                                sourceStack.topActivity().task == sourceRecord.task)) {
-                            // We really do want to push this one into the user's face, right now.
-                            if (launchTaskBehind && sourceRecord != null) {
-                                intentActivity.setTaskToAffiliateWith(sourceRecord.task);
-                            }
-                            movedHome = true;
-                            targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
-                                    options, r.appTimeTracker, "bringingFoundTaskToFront");
-                            movedToFront = true;
-                            if ((launchFlags &
-                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                                // Caller wants to appear on home activity.
-                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-                            }
-                            options = null;
-                        }
-                    }
-                    if (!movedToFront && doResume) {
-                        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
-                                + " from " + intentActivity);
-                        targetStack.moveToFront("intentActivityFound");
-                    }
-
-                    // If the caller has requested that the target task be
-                    // reset, then do so.
-                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
-                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
-                    }
-                    if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                        // We don't need to start a new activity, and
-                        // the client said not to do anything if that
-                        // is the case, so this is it!  And for paranoia, make
-                        // sure we have correctly resumed the top activity.
-                        if (doResume) {
-                            resumeTopActivitiesLocked(targetStack, null, options);
-
-                            // Make sure to notify Keyguard as well if we are not running an app
-                            // transition later.
-                            if (!movedToFront) {
-                                notifyActivityDrawnForKeyguard();
-                            }
-                        } else {
-                            ActivityOptions.abort(options);
-                        }
-                        updateUserStackLocked(r.userId, targetStack);
-                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                    }
-                    if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
-                        // The caller has requested to completely replace any
-                        // existing task with its new activity.  Well that should
-                        // not be too hard...
-                        reuseTask = intentActivity.task;
-                        reuseTask.performClearTaskLocked();
-                        reuseTask.setIntent(r);
-                    } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
-                            || launchSingleInstance || launchSingleTask) {
-                        // In this situation we want to remove all activities
-                        // from the task up to the one being started.  In most
-                        // cases this means we are resetting the task to its
-                        // initial state.
-                        ActivityRecord top =
-                                intentActivity.task.performClearTaskLocked(r, launchFlags);
-                        if (top != null) {
-                            if (top.frontOfTask) {
-                                // Activity aliases may mean we use different
-                                // intents for the top activity, so make sure
-                                // the task now has the identity of the new
-                                // intent.
-                                top.task.setIntent(r);
-                            }
-                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
-                                    r, top.task);
-                            top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                        } else {
-                            // A special case: we need to start the activity because it is not
-                            // currently running, and the caller has asked to clear the current
-                            // task to have this activity at the top.
-                            addingToTask = true;
-                            // Now pretend like this activity is being started by the top of its
-                            // task, so it is put in the right place.
-                            sourceRecord = intentActivity;
-                            TaskRecord task = sourceRecord.task;
-                            if (task != null && task.stack == null) {
-                                // Target stack got cleared when we all activities were removed
-                                // above. Go ahead and reset it.
-                                targetStack = computeStackFocus(
-                                        sourceRecord, false /* newTask */, null /* bounds */);
-                                targetStack.addTask(task,
-                                        !launchTaskBehind /* toTop */, "startActivityUnchecked");
-                            }
-
-                        }
-                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
-                        // In this case the top activity on the task is the
-                        // same as the one being launched, so we take that
-                        // as a request to bring the task to the foreground.
-                        // If the top activity in the task is the root
-                        // activity, deliver this new intent to it if it
-                        // desires.
-                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
-                                && intentActivity.realActivity.equals(r.realActivity)) {
-                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
-                                    intentActivity.task);
-                            if (intentActivity.frontOfTask) {
-                                intentActivity.task.setIntent(r);
-                            }
-                            intentActivity.deliverNewIntentLocked(callingUid, r.intent,
-                                    r.launchedFromPackage);
-                        } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
-                            // In this case we are launching the root activity
-                            // of the task, but with a different intent.  We
-                            // should start a new instance on top.
-                            addingToTask = true;
-                            sourceRecord = intentActivity;
-                        }
-                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
-                        // In this case an activity is being launched in to an
-                        // existing task, without resetting that task.  This
-                        // is typically the situation of launching an activity
-                        // from a notification or shortcut.  We want to place
-                        // the new activity on top of the current task.
-                        addingToTask = true;
-                        sourceRecord = intentActivity;
-                    } else if (!intentActivity.task.rootWasReset) {
-                        // In this case we are launching in to an existing task
-                        // that has not yet been started from its front door.
-                        // The current task has been brought to the front.
-                        // Ideally, we'd probably like to place this new task
-                        // at the bottom of its stack, but that's a little hard
-                        // to do with the current organization of the code so
-                        // for now we'll just drop it.
-                        intentActivity.task.setIntent(r);
-                    }
-                    if (!addingToTask && reuseTask == null) {
-                        // We didn't do anything...  but it was needed (a.k.a., client
-                        // don't use that intent!)  And for paranoia, make
-                        // sure we have correctly resumed the top activity.
-                        if (doResume) {
-                            targetStack.resumeTopActivityLocked(null, options);
-                            if (!movedToFront) {
-                                // Make sure to notify Keyguard as well if we are not running an app
-                                // transition later.
-                                notifyActivityDrawnForKeyguard();
-                            }
-                        } else {
-                            ActivityOptions.abort(options);
-                        }
-                        updateUserStackLocked(r.userId, targetStack);
-                        return ActivityManager.START_TASK_TO_FRONT;
-                    }
+                    options = null;
                 }
             }
+            if (!movedToFront && doResume) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
+                        + " from " + intentActivity);
+                targetStack.moveToFront("intentActivityFound");
+            }
+
+            // If the caller has requested that the target task be
+            // reset, then do so.
+            if ((launchFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+                intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
+            }
+            if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
+                // We don't need to start a new activity, and
+                // the client said not to do anything if that
+                // is the case, so this is it!  And for paranoia, make
+                // sure we have correctly resumed the top activity.
+                if (doResume) {
+                    resumeTopActivitiesLocked(targetStack, null, options);
+
+                    // Make sure to notify Keyguard as well if we are not running an app
+                    // transition later.
+                    if (!movedToFront) {
+                        notifyActivityDrawnForKeyguard();
+                    }
+                } else {
+                    ActivityOptions.abort(options);
+                }
+                updateUserStackLocked(r.userId, targetStack);
+                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
+            }
+            if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
+                // The caller has requested to completely replace any
+                // existing task with its new activity.  Well that should
+                // not be too hard...
+                reuseTask = intentActivity.task;
+                reuseTask.performClearTaskLocked();
+                reuseTask.setIntent(r);
+            } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
+                    || launchSingleInstance || launchSingleTask) {
+                // In this situation we want to remove all activities
+                // from the task up to the one being started.  In most
+                // cases this means we are resetting the task to its
+                // initial state.
+                ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
+                if (top != null) {
+                    if (top.frontOfTask) {
+                        // Activity aliases may mean we use different
+                        // intents for the top activity, so make sure
+                        // the task now has the identity of the new
+                        // intent.
+                        top.task.setIntent(r);
+                    }
+                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
+                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
+                } else {
+                    // A special case: we need to start the activity because it is not
+                    // currently running, and the caller has asked to clear the current
+                    // task to have this activity at the top.
+                    addingToTask = true;
+                    // Now pretend like this activity is being started by the top of its
+                    // task, so it is put in the right place.
+                    sourceRecord = intentActivity;
+                    TaskRecord task = sourceRecord.task;
+                    if (task != null && task.stack == null) {
+                        // Target stack got cleared when we all activities were removed
+                        // above. Go ahead and reset it.
+                        targetStack = computeStackFocus(
+                                sourceRecord, false /* newTask */, null /* bounds */);
+                        targetStack.addTask(task,
+                                !launchTaskBehind /* toTop */, "startActivityUnchecked");
+                    }
+
+                }
+            } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
+                // In this case the top activity on the task is the
+                // same as the one being launched, so we take that
+                // as a request to bring the task to the foreground.
+                // If the top activity in the task is the root
+                // activity, deliver this new intent to it if it
+                // desires.
+                if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
+                        && intentActivity.realActivity.equals(r.realActivity)) {
+                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
+                            intentActivity.task);
+                    if (intentActivity.frontOfTask) {
+                        intentActivity.task.setIntent(r);
+                    }
+                    intentActivity.deliverNewIntentLocked(callingUid, r.intent,
+                            r.launchedFromPackage);
+                } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
+                    // In this case we are launching the root activity
+                    // of the task, but with a different intent.  We
+                    // should start a new instance on top.
+                    addingToTask = true;
+                    sourceRecord = intentActivity;
+                }
+            } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+                // In this case an activity is being launched in to an
+                // existing task, without resetting that task.  This
+                // is typically the situation of launching an activity
+                // from a notification or shortcut.  We want to place
+                // the new activity on top of the current task.
+                addingToTask = true;
+                sourceRecord = intentActivity;
+            } else if (!intentActivity.task.rootWasReset) {
+                // In this case we are launching in to an existing task
+                // that has not yet been started from its front door.
+                // The current task has been brought to the front.
+                // Ideally, we'd probably like to place this new task
+                // at the bottom of its stack, but that's a little hard
+                // to do with the current organization of the code so
+                // for now we'll just drop it.
+                intentActivity.task.setIntent(r);
+            }
+            if (!addingToTask && reuseTask == null) {
+                // We didn't do anything...  but it was needed (a.k.a., client
+                // don't use that intent!)  And for paranoia, make
+                // sure we have correctly resumed the top activity.
+                if (doResume) {
+                    targetStack.resumeTopActivityLocked(null, options);
+                    if (!movedToFront) {
+                        // Make sure to notify Keyguard as well if we are not running an app
+                        // transition later.
+                        notifyActivityDrawnForKeyguard();
+                    }
+                } else {
+                    ActivityOptions.abort(options);
+                }
+                updateUserStackLocked(r.userId, targetStack);
+                return ActivityManager.START_TASK_TO_FRONT;
+            }
         }
 
         //String uri = r.intent.toURI();
@@ -2460,7 +2443,7 @@
 
         // Should this be considered a new task?
         if (r.resultTo == null && inTask == null && !addingToTask
-                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+                && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
             newTask = true;
             targetStack = computeStackFocus(r, newTask, newBounds);
             if (doResume) {
@@ -2628,9 +2611,14 @@
         }
         ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
         targetStack.mLastPausedActivity = null;
-        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
-        if (!launchTaskBehind && doResume) {
-            mService.setFocusedActivityLocked(r, "startedActivity");
+        targetStack.startActivityLocked(r, newTask, keepCurTransition, options);
+        if (doResume) {
+            if (!launchTaskBehind) {
+                mService.setFocusedActivityLocked(r, "startedActivity");
+            }
+            resumeTopActivitiesLocked(targetStack, r, options);
+        } else {
+            targetStack.addRecentActivityLocked(r);
         }
         updateUserStackLocked(r.userId, targetStack);
 
@@ -2641,6 +2629,37 @@
         return ActivityManager.START_SUCCESS;
     }
 
+    /**
+     * Decide whether the new activity should be inserted into an existing task. Returns null if not
+     * or an ActivityRecord with the task into which the new activity should be added.
+     */
+    private ActivityRecord getReusableIntentActivity(ActivityRecord r, TaskRecord inTask, Intent intent,
+            boolean launchSingleInstance, boolean launchSingleTask, int launchFlags) {
+        // We may want to try to place the new activity in to an existing task.  We always
+        // do this if the target activity is singleTask or singleInstance; we will also do
+        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
+        // us to still place it in a new task: multi task, always doc mode, or being asked to
+        // launch this as a new task behind the current one.
+        boolean putIntoExistingTask = ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                (launchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+                || launchSingleInstance || launchSingleTask;
+        // If bring to front is requested, and no result is requested and we have not
+        // been given an explicit task to launch in to, and
+        // we can find a task that was started with this same
+        // component, then instead of launching bring that one to the front.
+        putIntoExistingTask &= inTask == null && r.resultTo == null;
+        ActivityRecord intentActivity = null;
+        if (putIntoExistingTask) {
+            // See if there is a task to bring to the front.  If this is
+            // a SINGLE_INSTANCE activity, there can be one and only one
+            // instance of it in the history, and it is always in its own
+            // unique task, so we do a special search.
+            intentActivity = launchSingleInstance ?
+                    findActivityLocked(intent, r.info) : findTaskLocked(r);
+        }
+        return intentActivity;
+    }
+
     final void doPendingActivityLaunchesLocked(boolean doResume) {
         while (!mPendingActivityLaunches.isEmpty()) {
             PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
@@ -3119,6 +3138,14 @@
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
         mWindowManager.deferSurfaceLayout();
         try {
+
+            if (bounds != null && mWindowManager.isFullscreenBounds(stackId, bounds)) {
+                // The bounds passed in corresponds to the fullscreen bounds which we normally
+                // represent with null. Go ahead and set it to null so that all tasks configuration
+                // can have the right fullscreen state.
+                bounds = null;
+            }
+
             ActivityRecord r = stack.topRunningActivityLocked();
 
             mTmpBounds.clear();
@@ -3460,7 +3487,7 @@
         if (!r.info.supportsPip) {
             Slog.w(TAG,
                     "moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
-                    + " r=" + r);
+                            + " r=" + r);
             return false;
         }
 
@@ -4516,6 +4543,10 @@
         return mLockTaskModeState;
     }
 
+    void logStackState() {
+        mActivityMetricsLogger.logWindowState();
+    }
+
     private final class ActivityStackSupervisorHandler extends Handler {
 
         public ActivityStackSupervisorHandler(Looper looper) {
@@ -4695,8 +4726,8 @@
     }
 
     class ActivityContainer extends android.app.IActivityContainer.Stub {
-        final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
-                Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
+        final static int FORCE_NEW_TASK_FLAGS = FLAG_ACTIVITY_NEW_TASK |
+                FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
         final int mStackId;
         IActivityContainerCallback mCallback = null;
         final ActivityStack mStack;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2fb71c3..622aa16 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -468,7 +468,7 @@
     }
 
     private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
-            BroadcastFilter filter, boolean ordered) {
+            BroadcastFilter filter, boolean ordered, int index) {
         boolean skip = false;
         if (filter.requiredPermission != null) {
             int perm = mService.checkComponentPermission(filter.requiredPermission,
@@ -576,64 +576,70 @@
 
         if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
                 r.callingPid, r.resolvedType, filter.receiverList.uid)) {
-            return;
+            skip = true;
         }
 
-        if (filter.receiverList.app == null || filter.receiverList.app.crashing) {
+        if (!skip && (filter.receiverList.app == null || filter.receiverList.app.crashing)) {
             Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
                     + " to " + filter.receiverList + ": process crashing");
             skip = true;
         }
 
-        if (!skip) {
-            // If permissions need a review before any of the app components can run, we drop
-            // the broadcast and if the calling app is in the foreground and the broadcast is
-            // explicit we launch the review UI passing it a pending intent to send the skipped
-            // broadcast.
-            if (Build.PERMISSIONS_REVIEW_REQUIRED) {
-                if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
-                        filter.owningUserId)) {
-                    return;
-                }
-            }
+        if (skip) {
+            r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
+            return;
+        }
 
-            // If this is not being sent as an ordered broadcast, then we
-            // don't want to touch the fields that keep track of the current
-            // state of ordered broadcasts.
-            if (ordered) {
-                r.receiver = filter.receiverList.receiver.asBinder();
-                r.curFilter = filter;
-                filter.receiverList.curBroadcast = r;
-                r.state = BroadcastRecord.CALL_IN_RECEIVE;
-                if (filter.receiverList.app != null) {
-                    // Bump hosting application to no longer be in background
-                    // scheduling class.  Note that we can't do that if there
-                    // isn't an app...  but we can only be in that case for
-                    // things that directly call the IActivityManager API, which
-                    // are already core system stuff so don't matter for this.
-                    r.curApp = filter.receiverList.app;
-                    filter.receiverList.app.curReceiver = r;
-                    mService.updateOomAdjLocked(r.curApp);
-                }
+        // If permissions need a review before any of the app components can run, we drop
+        // the broadcast and if the calling app is in the foreground and the broadcast is
+        // explicit we launch the review UI passing it a pending intent to send the skipped
+        // broadcast.
+        if (Build.PERMISSIONS_REVIEW_REQUIRED) {
+            if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
+                    filter.owningUserId)) {
+                r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
+                return;
             }
-            try {
-                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
-                        "Delivering to " + filter + " : " + r);
-                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
-                        new Intent(r.intent), r.resultCode, r.resultData,
-                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
-                if (ordered) {
-                    r.state = BroadcastRecord.CALL_DONE_RECEIVE;
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
-                if (ordered) {
-                    r.receiver = null;
-                    r.curFilter = null;
-                    filter.receiverList.curBroadcast = null;
-                    if (filter.receiverList.app != null) {
-                        filter.receiverList.app.curReceiver = null;
-                    }
+        }
+
+        r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;
+
+        // If this is not being sent as an ordered broadcast, then we
+        // don't want to touch the fields that keep track of the current
+        // state of ordered broadcasts.
+        if (ordered) {
+            r.receiver = filter.receiverList.receiver.asBinder();
+            r.curFilter = filter;
+            filter.receiverList.curBroadcast = r;
+            r.state = BroadcastRecord.CALL_IN_RECEIVE;
+            if (filter.receiverList.app != null) {
+                // Bump hosting application to no longer be in background
+                // scheduling class.  Note that we can't do that if there
+                // isn't an app...  but we can only be in that case for
+                // things that directly call the IActivityManager API, which
+                // are already core system stuff so don't matter for this.
+                r.curApp = filter.receiverList.app;
+                filter.receiverList.app.curReceiver = r;
+                mService.updateOomAdjLocked(r.curApp);
+            }
+        }
+        try {
+            if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
+                    "Delivering to " + filter + " : " + r);
+            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
+                    new Intent(r.intent), r.resultCode, r.resultData,
+                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
+            if (ordered) {
+                r.state = BroadcastRecord.CALL_DONE_RECEIVE;
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
+            if (ordered) {
+                r.receiver = null;
+                r.curFilter = null;
+                filter.receiverList.curBroadcast = null;
+                if (filter.receiverList.app != null) {
+                    filter.receiverList.app.curReceiver = null;
                 }
             }
         }
@@ -740,7 +746,7 @@
                     if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                             "Delivering non-ordered on [" + mQueueName + "] to registered "
                             + target + ": " + r);
-                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
+                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                 }
                 addBroadcastToHistoryLocked(r);
                 if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
@@ -897,7 +903,7 @@
                         "Delivering ordered ["
                         + mQueueName + "] to registered "
                         + filter + ": " + r);
-                deliverToRegisteredReceiverLocked(r, filter, r.ordered);
+                deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
                 if (r.receiver == null || !r.ordered) {
                     // The receiver has already finished, so schedule to
                     // process the next one.
@@ -925,10 +931,17 @@
                     info.activityInfo.name);
 
             boolean skip = false;
+            if (brOptions != null &&
+                    (info.activityInfo.applicationInfo.targetSdkVersion
+                            < brOptions.getMinManifestReceiverApiLevel() ||
+                    info.activityInfo.applicationInfo.targetSdkVersion
+                            > brOptions.getMaxManifestReceiverApiLevel())) {
+                skip = true;
+            }
             int perm = mService.checkComponentPermission(info.activityInfo.permission,
                     r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
                     info.activityInfo.exported);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
+            if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
                 if (!info.activityInfo.exported) {
                     Slog.w(TAG, "Permission Denial: broadcasting "
                             + r.intent.toString()
@@ -945,7 +958,7 @@
                             + " due to receiver " + component.flattenToShortString());
                 }
                 skip = true;
-            } else if (info.activityInfo.permission != null) {
+            } else if (!skip && info.activityInfo.permission != null) {
                 final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
                 if (opCode != AppOpsManager.OP_NONE
                         && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
@@ -1075,9 +1088,18 @@
                 }
             }
 
+            // This is safe to do even if we are skipping the broadcast, and we need
+            // this information now to evaluate whether it is going to be allowed to run.
+            final int receiverUid = info.activityInfo.applicationInfo.uid;
+            // If it's a singleton, it needs to be the same app or a special app
+            if (r.callingUid != Process.SYSTEM_UID && isSingleton
+                    && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
+                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
+            }
             String targetProcess = info.activityInfo.processName;
             ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
                     info.activityInfo.applicationInfo.uid, false);
+
             if (!skip) {
                 final int allowed = mService.checkAllowBackgroundLocked(
                         info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1);
@@ -1086,9 +1108,17 @@
                     // completely disabled from launches, or it is delayed and the broadcast
                     // was not explicitly sent to it and this would result in a new process
                     // for it being created.
-                    if (allowed == ActivityManager.APP_START_MODE_DISABLED
+                    if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
+                        Slog.w(TAG, "Background execution disabled: receiving "
+                                + r.intent + " to "
+                                + component.flattenToShortString());
+                        skip = true;
+                    }
+                    if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                             || (r.intent.getComponent() == null
-                            && r.intent.getPackage() == null && app == null)) {
+                                && r.intent.getPackage() == null && app == null
+                                && ((r.intent.getFlags()
+                                        & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0))) {
                         Slog.w(TAG, "Background execution not allowed: receiving "
                                 + r.intent + " to "
                                 + component.flattenToShortString());
@@ -1101,6 +1131,7 @@
                 if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Skipping delivery of ordered [" + mQueueName + "] "
                         + r + " for whatever reason");
+                r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
                 r.receiver = null;
                 r.curFilter = null;
                 r.state = BroadcastRecord.IDLE;
@@ -1108,14 +1139,9 @@
                 return;
             }
 
+            r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
             r.state = BroadcastRecord.APP_RECEIVE;
             r.curComponent = component;
-            final int receiverUid = info.activityInfo.applicationInfo.uid;
-            // If it's a singleton, it needs to be the same app or a special app
-            if (r.callingUid != Process.SYSTEM_UID && isSingleton
-                    && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
-                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
-            }
             r.curReceiver = info.activityInfo;
             if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
                 Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
@@ -1283,6 +1309,7 @@
         String anrMessage = null;
 
         Object curReceiver = r.receivers.get(r.nextReceiver-1);
+        r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
         Slog.w(TAG, "Receiver during timeout: " + curReceiver);
         logBroadcastReceiverDiscardLocked(r);
         if (curReceiver instanceof BroadcastFilter) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index b42bcff..e99cbf9 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -57,6 +57,7 @@
     final int appOp;        // an app op that is associated with this broadcast
     final BroadcastOptions options; // BroadcastOptions supplied by caller
     final List receivers;   // contains BroadcastFilter and ResolveInfo
+    final int[] delivery;   // delivery state of each receiver
     IIntentReceiver resultTo; // who receives final result if non-null
     long enqueueClockTime;  // the clock time the broadcast was enqueued
     long dispatchTime;      // when dispatch started on this set of receivers
@@ -79,6 +80,11 @@
     static final int CALL_DONE_RECEIVE = 3;
     static final int WAITING_SERVICES = 4;
 
+    static final int DELIVERY_PENDING = 0;
+    static final int DELIVERY_DELIVERED = 1;
+    static final int DELIVERY_SKIPPED = 2;
+    static final int DELIVERY_TIMEOUT = 3;
+
     // The following are set when we are calling a receiver (one that
     // was found in our list of registered receivers).
     BroadcastFilter curFilter;
@@ -183,12 +189,24 @@
         PrintWriterPrinter printer = new PrintWriterPrinter(pw);
         for (int i = 0; i < N; i++) {
             Object o = receivers.get(i);
-            pw.print(prefix); pw.print("Receiver #"); pw.print(i);
-                    pw.print(": "); pw.println(o);
-            if (o instanceof BroadcastFilter)
-                ((BroadcastFilter)o).dumpBrief(pw, p2);
-            else if (o instanceof ResolveInfo)
-                ((ResolveInfo)o).dump(printer, p2);
+            pw.print(prefix);
+            switch (delivery[i]) {
+                case DELIVERY_PENDING:   pw.print("Pending"); break;
+                case DELIVERY_DELIVERED: pw.print("Deliver"); break;
+                case DELIVERY_SKIPPED:   pw.print("Skipped"); break;
+                case DELIVERY_TIMEOUT:   pw.print("Timeout"); break;
+                default:                 pw.print("???????"); break;
+            }
+            pw.print(" #"); pw.print(i); pw.print(": ");
+            if (o instanceof BroadcastFilter) {
+                pw.println(o);
+                ((BroadcastFilter) o).dumpBrief(pw, p2);
+            } else if (o instanceof ResolveInfo) {
+                pw.println("(manifest)");
+                ((ResolveInfo) o).dump(printer, p2, 0);
+            } else {
+                pw.println(o);
+            }
         }
     }
 
@@ -211,6 +229,7 @@
         appOp = _appOp;
         options = _options;
         receivers = _receivers;
+        delivery = new int[_receivers != null ? _receivers.size() : 0];
         resultTo = _resultTo;
         resultCode = _resultCode;
         resultData = _resultData;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index f6f82da..62e78a4 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -253,7 +253,8 @@
 
                 final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                 bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+                bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+                        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                 mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null,
                         new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
                         AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4f2f486..40d01e7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -197,7 +197,7 @@
     private static final int MSG_SET_DEVICE_VOLUME = 0;
     private static final int MSG_PERSIST_VOLUME = 1;
     private static final int MSG_PERSIST_RINGER_MODE = 3;
-    private static final int MSG_MEDIA_SERVER_DIED = 4;
+    private static final int MSG_AUDIO_SERVER_DIED = 4;
     private static final int MSG_PLAY_SOUND_EFFECT = 5;
     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
     private static final int MSG_LOAD_SOUND_EFFECTS = 7;
@@ -358,7 +358,7 @@
         public void onError(int error) {
             switch (error) {
             case AudioSystem.AUDIO_STATUS_SERVER_DIED:
-                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
+                sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
                         SENDMSG_NOOP, 0, 0, null, 0);
                 break;
             default:
@@ -772,15 +772,15 @@
                 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
     }
 
-    public void onMediaServerDied() {
+    public void onAudioServerDied() {
         if (!mSystemReady ||
                 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
-            Log.e(TAG, "Media server died.");
-            sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
+            Log.e(TAG, "Audioserver died.");
+            sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
                     null, 500);
             return;
         }
-        Log.e(TAG, "Media server started.");
+        Log.e(TAG, "Audioserver started.");
 
         // indicate to audio HAL that we start the reconfiguration phase after a media
         // server crash
@@ -4406,8 +4406,8 @@
                     persistRingerMode(getRingerModeInternal());
                     break;
 
-                case MSG_MEDIA_SERVER_DIED:
-                    onMediaServerDied();
+                case MSG_AUDIO_SERVER_DIED:
+                    onAudioServerDied();
                     break;
 
                 case MSG_UNLOAD_SOUND_EFFECTS:
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index a066835..78618ce 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -345,25 +345,9 @@
     }
 
     public void updateRunningAccounts() {
-        mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
-
-        if (mBootCompleted) {
-            doDatabaseCleanup();
-        }
-
-        AccountAndUser[] accounts = mRunningAccounts;
-        for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
-            if (!containsAccountAndUser(accounts,
-                    currentSyncContext.mSyncOperation.target.account,
-                    currentSyncContext.mSyncOperation.target.userId)) {
-                Log.d(TAG, "canceling sync since the account is no longer running");
-                sendSyncFinishedOrCanceledMessage(currentSyncContext,
-                        null /* no result since this is a cancel */);
-            }
-        }
-        // we must do this since we don't bother scheduling alarms when
-        // the accounts are not set yet
-        sendCheckAlarmsMessage();
+        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_ACCOUNTS_UPDATED");
+        // Update accounts in handler thread.
+        mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_ACCOUNTS_UPDATED);
     }
 
     private void doDatabaseCleanup() {
@@ -2179,6 +2163,7 @@
          * obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
          */
         private static final int MESSAGE_MONITOR_SYNC = 8;
+        private static final int MESSAGE_ACCOUNTS_UPDATED = 9;
 
         public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
         private Long mAlarmScheduleTime = null;
@@ -2296,6 +2281,13 @@
                 // to also take into account the periodic syncs.
                 earliestFuturePollTime = scheduleReadyPeriodicSyncs();
                 switch (msg.what) {
+                    case SyncHandler.MESSAGE_ACCOUNTS_UPDATED:
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
+                        }
+                        updateRunningAccountsH();
+                        break;
+
                     case SyncHandler.MESSAGE_CANCEL:
                         SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
                         Bundle extras = msg.peekData();
@@ -2872,7 +2864,28 @@
                     mLocalDeviceIdleController.setSyncActive(active);
                 }
             }
+        }
 
+        private void updateRunningAccountsH() {
+            mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
+
+            if (mBootCompleted) {
+                doDatabaseCleanup();
+            }
+
+            AccountAndUser[] accounts = mRunningAccounts;
+            for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
+                if (!containsAccountAndUser(accounts,
+                        currentSyncContext.mSyncOperation.target.account,
+                        currentSyncContext.mSyncOperation.target.userId)) {
+                    Log.d(TAG, "canceling sync since the account is no longer running");
+                    sendSyncFinishedOrCanceledMessage(currentSyncContext,
+                            null /* no result since this is a cancel */);
+                }
+            }
+            // we must do this since we don't bother scheduling alarms when
+            // the accounts are not set yet
+            sendCheckAlarmsMessage();
         }
 
         private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index e15bca6..1908f72 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -49,23 +49,12 @@
     // If true, enables the use of the screen auto-brightness adjustment setting.
     private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
 
-    // The maximum range of gamma adjustment possible using the screen
-    // auto-brightness adjustment setting.
-    private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
-
-    // Period of time in which to consider light samples in milliseconds.
-    private static final int AMBIENT_LIGHT_HORIZON = 10000;
-
     // Hysteresis constraints for brightening or darkening.
     // The recent lux must have changed by at least this fraction relative to the
     // current ambient lux before a change will be considered.
     private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
     private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
 
-    // The intercept used for the weighting calculation. This is used in order to keep all possible
-    // weighting values positive.
-    private static final int WEIGHTING_INTERCEPT = AMBIENT_LIGHT_HORIZON;
-
     // How long the current sensor reading is assumed to be valid beyond the current time.
     // This provides a bit of prediction, as well as ensures that the weight for the last sample is
     // non-zero, which in turn ensures that the total weight is non-zero.
@@ -132,6 +121,13 @@
     // and only then decide whether to change brightness.
     private final boolean mResetAmbientLuxAfterWarmUpConfig;
 
+    // Period of time in which to consider light samples in milliseconds.
+    private final int mAmbientLightHorizon;
+
+    // The intercept used for the weighting calculation. This is used in order to keep all possible
+    // weighting values positive.
+    private final int mWeightingIntercept;
+
     // Amount of time to delay auto-brightness after screen on while waiting for
     // the light sensor to warm-up in milliseconds.
     // May be 0 if no warm-up is required.
@@ -179,6 +175,10 @@
     // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter)
     private float mScreenAutoBrightnessAdjustment = 0.0f;
 
+    // The maximum range of gamma adjustment possible using the screen
+    // auto-brightness adjustment setting.
+    private float mScreenAutoBrightnessAdjustmentMaxGamma;
+
     // The last screen auto-brightness gamma.  (For printing in dump() only.)
     private float mLastScreenAutoBrightnessGamma = 1.0f;
 
@@ -197,7 +197,8 @@
             SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
             int brightnessMin, int brightnessMax, float dozeScaleFactor,
             int lightSensorRate, long brighteningLightDebounceConfig,
-            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig) {
+            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
+            int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma ) {
         mCallbacks = callbacks;
         mTwilight = LocalServices.getService(TwilightManager.class);
         mSensorManager = sensorManager;
@@ -210,9 +211,12 @@
         mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
         mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
         mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
+        mAmbientLightHorizon = ambientLightHorizon;
+        mWeightingIntercept = ambientLightHorizon;
+        mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
 
         mHandler = new AutomaticBrightnessHandler(looper);
-        mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate);
+        mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
 
         if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
             mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -266,6 +270,7 @@
         pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
         pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
         pw.println("  mAmbientLux=" + mAmbientLux);
+        pw.println("  mAmbientLightHorizon=" + mAmbientLightHorizon);
         pw.println("  mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
         pw.println("  mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
         pw.println("  mLastObservedLux=" + mLastObservedLux);
@@ -274,6 +279,7 @@
         pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
         pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
         pw.println("  mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
+        pw.println("  mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma);
         pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
         pw.println("  mDozing=" + mDozing);
     }
@@ -309,7 +315,7 @@
 
     private void applyLightSensorMeasurement(long time, float lux) {
         mRecentLightSamples++;
-        mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
+        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
         mAmbientLightRingBuffer.push(time, lux);
 
         // Remember this sample value.
@@ -360,14 +366,14 @@
         return sum / totalWeight;
     }
 
-    private static float calculateWeight(long startDelta, long endDelta) {
+    private float calculateWeight(long startDelta, long endDelta) {
         return weightIntegral(endDelta) - weightIntegral(startDelta);
     }
 
-    // Evaluates the integral of y = x + WEIGHTING_INTERCEPT. This is always positive for the
+    // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
     // horizon we're looking at and provides a non-linear weighting for light samples.
-    private static float weightIntegral(long x) {
-        return x * (x * 0.5f + WEIGHTING_INTERCEPT);
+    private float weightIntegral(long x) {
+        return x * (x * 0.5f + mWeightingIntercept);
     }
 
     private long nextAmbientLightBrighteningTransition(long time) {
@@ -396,7 +402,7 @@
 
     private void updateAmbientLux() {
         long time = SystemClock.uptimeMillis();
-        mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
+        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
         updateAmbientLux(time);
     }
 
@@ -470,7 +476,7 @@
 
         if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
                 && mScreenAutoBrightnessAdjustment != 0.0f) {
-            final float adjGamma = MathUtils.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
+            final float adjGamma = MathUtils.pow(mScreenAutoBrightnessAdjustmentMaxGamma,
                     Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
             gamma *= adjGamma;
             if (DEBUG) {
@@ -653,8 +659,8 @@
         private int mEnd;
         private int mCount;
 
-        public AmbientLightRingBuffer(long lightSensorRate) {
-            mCapacity = (int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / lightSensorRate);
+        public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
+            mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
             mRingLux = new float[mCapacity];
             mRingTime = new long[mCapacity];
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 7b49530..433d887 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -311,6 +311,11 @@
                 com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
         boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
                 com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
+        int ambientLightHorizon = resources.getInteger(
+                com.android.internal.R.integer.config_autoBrightnessAmbientLightHorizon);
+        float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
+                com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
+                1, 1);
 
         if (mUseSoftwareAutoBrightnessConfig) {
             int[] lux = resources.getIntArray(
@@ -348,7 +353,8 @@
                         lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
                         mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                         brighteningLightDebounce, darkeningLightDebounce,
-                        autoBrightnessResetAmbientLuxAfterWarmUp);
+                        autoBrightnessResetAmbientLuxAfterWarmUp,
+                        ambientLightHorizon, autoBrightnessAdjustmentMaxGamma);
             }
         }
 
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index e0a9975..7ac3c4b 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -189,7 +189,7 @@
     protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
         if (fingerIds.length != groupIds.length) {
             Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
-                    + fingerIds + ", g[]=" + groupIds);
+                    + Arrays.toString(fingerIds) + ", g[]=" + Arrays.toString(groupIds));
             return;
         }
         if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 11fdb92..459c47f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -523,7 +523,9 @@
                 case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
                     for (int type : mLocalDevices) {
                         HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
-                        localDevice.setAutoDeviceOff(enabled);
+                        if (localDevice != null) {
+                            localDevice.setAutoDeviceOff(enabled);
+                        }
                     }
                     // No need to propagate to HAL.
                     break;
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index f2d0031..8b37383 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -213,6 +213,7 @@
     private static native void nativeMonitor(long ptr);
     private static native void nativeSetPointerIconShape(long ptr, int iconId);
     private static native void nativeReloadPointerIcons(long ptr);
+    private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
 
     // Input event injection constants defined in InputDispatcher.h.
     private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
@@ -1451,6 +1452,12 @@
         nativeSetPointerIconShape(mPtr, iconId);
     }
 
+    // Binder call
+    @Override
+    public void setCustomPointerIcon(PointerIcon icon) {
+        nativeSetCustomPointerIcon(mPtr, icon);
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 4d7df9c..309bec8 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -88,6 +88,7 @@
     static final int MSG_JOB_EXPIRED = 0;
     static final int MSG_CHECK_JOB = 1;
     static final int MSG_STOP_JOB = 2;
+    static final int MSG_CHECK_JOB_GREEDY = 3;
 
     // Policy constants
     /**
@@ -362,7 +363,8 @@
     }
 
     void reportActive() {
-        boolean active = false;
+        // active is true if pending queue contains jobs OR some job is running.
+        boolean active = mPendingJobs.size() > 0;
         if (mPendingJobs.size() <= 0) {
             for (int i=0; i<mActiveServices.size(); i++) {
                 JobServiceContext jsc = mActiveServices.get(i);
@@ -372,9 +374,10 @@
                 }
             }
         }
-        if (mLocalDeviceIdleController != null) {
-            if (mReportedActive != active) {
-                mReportedActive = active;
+
+        if (mReportedActive != active) {
+            mReportedActive = active;
+            if (mLocalDeviceIdleController != null) {
                 mLocalDeviceIdleController.setJobsActive(active);
             }
         }
@@ -628,7 +631,8 @@
             JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
             startTrackingJob(rescheduledPeriodic);
         }
-        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+        reportActive();
+        mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
     }
 
     // StateChangedListener implementations.
@@ -676,8 +680,18 @@
                     break;
                 case MSG_CHECK_JOB:
                     synchronized (mJobs) {
-                        // Check the list of jobs and run some of them if we feel inclined.
-                        maybeQueueReadyJobsForExecutionLockedH();
+                        if (mReportedActive) {
+                            // if jobs are currently being run, queue all ready jobs for execution.
+                            queueReadyJobsForExecutionLockedH();
+                        } else {
+                            // Check the list of jobs and run some of them if we feel inclined.
+                            maybeQueueReadyJobsForExecutionLockedH();
+                        }
+                    }
+                    break;
+                case MSG_CHECK_JOB_GREEDY:
+                    synchronized (mJobs) {
+                        queueReadyJobsForExecutionLockedH();
                     }
                     break;
                 case MSG_STOP_JOB:
@@ -709,7 +723,6 @@
                     stopJobOnServiceContextLocked(job);
                 }
             }
-            reportActive();
             if (DEBUG) {
                 final int queuedJobs = mPendingJobs.size();
                 if (queuedJobs == 0) {
@@ -786,7 +799,6 @@
                     Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
                 }
             }
-            reportActive();
             if (DEBUG) {
                 Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
                 connectivityCount + " charging=" + chargingCount + " tot=" +
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index b3d7287..33b09e3 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -17,11 +17,8 @@
 package com.android.server.job.controllers;
 
 import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
+import android.app.AlarmManager.OnAlarmListener;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.SystemClock;
 import android.util.Slog;
 
@@ -40,15 +37,11 @@
  */
 public class TimeController extends StateController {
     private static final String TAG = "JobScheduler.Time";
-    private static final String ACTION_JOB_EXPIRED =
-            "android.content.jobscheduler.JOB_DEADLINE_EXPIRED";
-    private static final String ACTION_JOB_DELAY_EXPIRED =
-            "android.content.jobscheduler.JOB_DELAY_EXPIRED";
 
-    /** Set an alarm for the next job expiry. */
-    private final PendingIntent mDeadlineExpiredAlarmIntent;
-    /** Set an alarm for the next job delay expiry. This*/
-    private final PendingIntent mNextDelayExpiredAlarmIntent;
+    /** Deadline alarm tag for logging purposes */
+    private final String DEADLINE_TAG = "deadline";
+    /** Delay alarm tag for logging purposes */
+    private final String DELAY_TAG = "delay";
 
     private long mNextJobExpiredElapsedMillis;
     private long mNextDelayExpiredElapsedMillis;
@@ -68,19 +61,9 @@
 
     private TimeController(StateChangedListener stateChangedListener, Context context) {
         super(stateChangedListener, context);
-        mDeadlineExpiredAlarmIntent =
-                PendingIntent.getBroadcast(mContext, 0 /* ignored */,
-                        new Intent(ACTION_JOB_EXPIRED), 0);
-        mNextDelayExpiredAlarmIntent =
-                PendingIntent.getBroadcast(mContext, 0 /* ignored */,
-                        new Intent(ACTION_JOB_DELAY_EXPIRED), 0);
+
         mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
         mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
-
-        // Register BR for these intents.
-        IntentFilter intentFilter = new IntentFilter(ACTION_JOB_EXPIRED);
-        intentFilter.addAction(ACTION_JOB_DELAY_EXPIRED);
-        mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
     }
 
     /**
@@ -224,7 +207,7 @@
     private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
         mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
-        updateAlarmWithPendingIntent(mNextDelayExpiredAlarmIntent, mNextDelayExpiredElapsedMillis);
+        updateAlarmWithListener(DELAY_TAG, mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis);
     }
 
     /**
@@ -235,7 +218,7 @@
     private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
         mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
-        updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextJobExpiredElapsedMillis);
+        updateAlarmWithListener(DEADLINE_TAG, mDeadlineExpiredListener, mNextJobExpiredElapsedMillis);
     }
 
     private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
@@ -246,31 +229,39 @@
         return proposedAlarmTimeElapsedMillis;
     }
 
-    private void updateAlarmWithPendingIntent(PendingIntent pi, long alarmTimeElapsed) {
+    private void updateAlarmWithListener(String tag, OnAlarmListener listener,
+            long alarmTimeElapsed) {
         ensureAlarmService();
         if (alarmTimeElapsed == Long.MAX_VALUE) {
-            mAlarmService.cancel(pi);
+            mAlarmService.cancel(listener);
         } else {
             if (DEBUG) {
-                Slog.d(TAG, "Setting " + pi.getIntent().getAction() + " for: " + alarmTimeElapsed);
+                Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
             }
-            mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsed, pi);
+            mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsed,
+                    tag, listener, null);
         }
     }
 
-    private final BroadcastReceiver mAlarmExpiredReceiver = new BroadcastReceiver() {
+    // Job/delay expiration alarm handling
+
+    private final OnAlarmListener mDeadlineExpiredListener = new OnAlarmListener() {
         @Override
-        public void onReceive(Context context, Intent intent) {
+        public void onAlarm() {
             if (DEBUG) {
-                Slog.d(TAG, "Just received alarm: " + intent.getAction());
+                Slog.d(TAG, "Deadline-expired alarm fired");
             }
-            // A job has just expired, so we run through the list of jobs that we have and
-            // notify our StateChangedListener.
-            if (ACTION_JOB_EXPIRED.equals(intent.getAction())) {
-                checkExpiredDeadlinesAndResetAlarm();
-            } else if (ACTION_JOB_DELAY_EXPIRED.equals(intent.getAction())) {
-                checkExpiredDelaysAndResetAlarm();
+            checkExpiredDeadlinesAndResetAlarm();
+        }
+    };
+
+    private final OnAlarmListener mNextDelayExpiredListener = new OnAlarmListener() {
+        @Override
+        public void onAlarm() {
+            if (DEBUG) {
+                Slog.d(TAG, "Delay-expired alarm fired");
             }
+            checkExpiredDelaysAndResetAlarm();
         }
     };
 
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index bc9f520..88ab2c6 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -88,6 +88,7 @@
 import java.io.StringReader;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.Map.Entry;
 import java.util.Properties;
@@ -1599,7 +1600,7 @@
         switch (status) {
             case GPS_REQUEST_AGPS_DATA_CONN:
                 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
-                Log.v(TAG, "Received SUPL IP addr[]: " + ipaddr);
+                Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
                 InetAddress connectionIpAddress = null;
                 if (ipaddr != null) {
                     try {
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index ec81fd2..32db000 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -32,11 +32,11 @@
             return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
         }
 
-        final int leftScore = left.sbn.getScore();
-        final int rightScore = right.sbn.getScore();
-        if (leftScore != rightScore) {
+        final int leftImportance = left.getImportance();
+        final int rightImportance = right.getImportance();
+        if (leftImportance != rightImportance) {
             // by priority, high to low
-            return -1 * Integer.compare(leftScore, rightScore);
+            return -1 * Integer.compare(leftImportance, rightImportance);
         }
 
         final float leftPeople = left.getContactAffinity();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 33f39bc..e6a48a8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -34,6 +34,7 @@
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
+import static  android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -159,8 +160,8 @@
 public class NotificationManagerService extends SystemService {
     static final String TAG = "NotificationService";
     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
-            && SystemProperties.getBoolean("debug.child_notifs", false);
+    public static final boolean ENABLE_CHILD_NOTIFICATIONS
+            = SystemProperties.getBoolean("debug.child_notifs", true);
 
     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
 
@@ -181,16 +182,6 @@
     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
 
     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
-    static final boolean SCORE_ONGOING_HIGHER = false;
-
-    static final int JUNK_SCORE = -1000;
-    static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-    static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
-
-    // Notifications with scores below this will not interrupt the user, either via LED or
-    // sound or vibration
-    static final int SCORE_INTERRUPTION_THRESHOLD =
-            Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
 
     static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
     static final boolean ENABLE_BLOCKED_TOASTS = true;
@@ -889,6 +880,9 @@
             @Override
             void onZenModeChanged() {
                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+                getContext().sendBroadcastAsUser(
+                        new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL),
+                        UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
                 synchronized(mNotificationList) {
                     updateInterruptionFilterLocked();
                 }
@@ -1246,7 +1240,7 @@
         @Override
         public void setTopicImportance(String pkg, int uid, Notification.Topic topic,
                 int importance) {
-            checkCallerIsSystem();
+            enforceSystemOrSystemUI("Caller not system or systemui");
             mRankingHelper.setTopicImportance(pkg, uid, topic, importance);
             savePolicyFile();
         }
@@ -2158,31 +2152,15 @@
 
                 synchronized (mNotificationList) {
 
-                    // === Scoring ===
-
-                    // 0. Sanitize inputs
+                    // Sanitize inputs
                     notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
                             Notification.PRIORITY_MAX);
-                    // Migrate notification flags to scores
-                    if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
-                        if (notification.priority < Notification.PRIORITY_MAX) {
-                            notification.priority = Notification.PRIORITY_MAX;
-                        }
-                    } else if (SCORE_ONGOING_HIGHER &&
-                            0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
-                        if (notification.priority < Notification.PRIORITY_HIGH) {
-                            notification.priority = Notification.PRIORITY_HIGH;
-                        }
-                    }
 
-                    // 1. initial score: buckets of 10, around the app [-20..20]
-                    final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;
-
-                    // 2. extract ranking signals from the notification data
+                    // setup local book-keeping
                     final StatusBarNotification n = new StatusBarNotification(
-                            pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
+                            pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
                             user);
-                    NotificationRecord r = new NotificationRecord(n, score);
+                    NotificationRecord r = new NotificationRecord(getContext(), n);
                     NotificationRecord old = mNotificationsByKey.get(n.getKey());
                     if (old != null) {
                         // Retain ranking information from previous record
@@ -2217,23 +2195,16 @@
                     mRankingHelper.extractSignals(r);
                     savePolicyFile();
 
-                    // 3. Apply local rules
-
                     // blocked apps
                     if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
                         if (!isSystemNotification) {
-                            r.score = JUNK_SCORE;
                             Slog.e(TAG, "Suppressing notification from package " + pkg
                                     + " by user request.");
                             mUsageStats.registerBlocked(r);
+                            return;
                         }
                     }
 
-                    if (r.score < SCORE_DISPLAY_THRESHOLD) {
-                        // Notification will be blocked because the score is too low.
-                        return;
-                    }
-
                     int index = indexOfNotificationLocked(n.getKey());
                     if (index < 0) {
                         mNotificationList.add(r);
@@ -2385,7 +2356,7 @@
         final Notification notification = record.sbn.getNotification();
 
         // Should this notification make noise, vibe, or use the LED?
-        final boolean aboveThreshold = record.score >= SCORE_INTERRUPTION_THRESHOLD;
+        final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_HIGH;
         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
         if (DBG || record.isIntercepted())
             Slog.v(TAG,
@@ -3251,24 +3222,29 @@
         final int N = mNotificationList.size();
         ArrayList<String> keys = new ArrayList<String>(N);
         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
+        ArrayList<Integer> importance = new ArrayList<>(N);
         Bundle visibilityOverrides = new Bundle();
         Bundle suppressedVisualEffects = new Bundle();
+        Bundle explanation = new Bundle();
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
             if (!isVisibleToListener(record.sbn, info)) {
                 continue;
             }
-            keys.add(record.sbn.getKey());
+            final String key = record.sbn.getKey();
+            keys.add(key);
+            importance.add(record.getImportance());
+            if (record.getImportanceExplanation() != null) {
+                explanation.putCharSequence(key, record.getImportanceExplanation());
+            }
             if (record.isIntercepted()) {
-                interceptedKeys.add(record.sbn.getKey());
+                interceptedKeys.add(key);
 
             }
-            suppressedVisualEffects.putInt(
-                    record.sbn.getKey(), record.getSuppressedVisualEffects());
+            suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
             if (record.getPackageVisibilityOverride()
                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
-                visibilityOverrides.putInt(record.sbn.getKey(),
-                        record.getPackageVisibilityOverride());
+                visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
             }
             // Find first min-prio notification for speedbump placement.
             if (speedBumpIndex == -1 &&
@@ -3283,10 +3259,15 @@
                 speedBumpIndex = keys.size() - 1;
             }
         }
-        String[] keysAr = keys.toArray(new String[keys.size()]);
+        final int M = keys.size();
+        String[] keysAr = keys.toArray(new String[M]);
         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
+        int[] importanceAr = new int[M];
+        for (int i = 0; i < M; i++) {
+            importanceAr[i] = importance.get(i);
+        }
         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
-                speedBumpIndex, suppressedVisualEffects);
+                speedBumpIndex, suppressedVisualEffects, importanceAr, explanation);
     }
 
     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
@@ -3705,7 +3686,7 @@
                     for (int i = 0; i < tokens.length; i++) {
                         String token = tokens[i];
                         if (token != null) {
-                            token.trim();
+                            token = token.trim();
                         }
                         if (TextUtils.isEmpty(token)) {
                             continue;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 3b7384e..a9f20a6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -15,6 +15,11 @@
  */
 package com.android.server.notification;
 
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_LOW;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
+
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -49,10 +54,10 @@
 public final class NotificationRecord {
     final StatusBarNotification sbn;
     final int mOriginalFlags;
+    private final Context mContext;
 
     NotificationUsageStats.SingleNotificationStats stats;
     boolean isCanceled;
-    int score;
     /** Whether the notification was seen by the user via one of the notification listeners. */
     boolean mIsSeen;
 
@@ -84,18 +89,71 @@
     private String mGlobalSortKey;
     private int mPackageVisibility;
     private int mTopicImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+    private int mImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+    private CharSequence mImportanceExplanation = null;
 
     private int mSuppressedVisualEffects = 0;
+    private String mTopicExplanation;
+    private String mPeopleExplanation;
 
     @VisibleForTesting
-    public NotificationRecord(StatusBarNotification sbn, int score)
+    public NotificationRecord(Context context, StatusBarNotification sbn)
     {
         this.sbn = sbn;
-        this.score = score;
         mOriginalFlags = sbn.getNotification().flags;
         mRankingTimeMs = calculateRankingTimeMs(0L);
         mCreationTimeMs = sbn.getPostTime();
         mUpdateTimeMs = mCreationTimeMs;
+        mContext = context;
+        mImportance = defaultImportance();
+    }
+
+    private int defaultImportance() {
+        final Notification n = sbn.getNotification();
+        int importance = IMPORTANCE_DEFAULT;
+
+        // Migrate notification flags to scores
+        if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
+            n.priority = Notification.PRIORITY_MAX;
+        }
+
+        switch (n.priority) {
+            case Notification.PRIORITY_MIN:
+            case Notification.PRIORITY_LOW:
+                importance = IMPORTANCE_LOW;
+                break;
+            case Notification.PRIORITY_DEFAULT:
+                importance = IMPORTANCE_DEFAULT;
+                break;
+            case Notification.PRIORITY_HIGH:
+                importance = IMPORTANCE_HIGH;
+                break;
+            case Notification.PRIORITY_MAX:
+                importance = IMPORTANCE_MAX;
+                break;
+        }
+
+        boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0
+                || (n.defaults & Notification.DEFAULT_VIBRATE) != 0
+                || n.sound != null
+                || n.vibrate != null;
+        if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
+            importance = IMPORTANCE_DEFAULT;
+        }
+        // maybe only do this for target API < N?
+        if (isNoisy) {
+            if (importance == IMPORTANCE_HIGH) {
+                importance = IMPORTANCE_MAX;
+            } else {
+                importance = IMPORTANCE_HIGH;
+            }
+        }
+
+        if (n.fullScreenIntent != null) {
+            importance = IMPORTANCE_MAX;
+        }
+
+        return importance;
     }
 
     // copy any notes that the ranking system may have made before the update
@@ -109,6 +167,8 @@
         mCreationTimeMs = previous.mCreationTimeMs;
         mVisibleSinceMs = previous.mVisibleSinceMs;
         mTopicImportance = previous.mTopicImportance;
+        mImportance = previous.mImportance;
+        mImportanceExplanation = previous.mImportanceExplanation;
         // Don't copy mGlobalSortKey, recompute it.
     }
 
@@ -129,7 +189,7 @@
         pw.println(prefix + this);
         pw.println(prefix + "  uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
         pw.println(prefix + "  icon=" + iconStr);
-        pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.getScore());
+        pw.println(prefix + "  pri=" + notification.priority);
         pw.println(prefix + "  key=" + sbn.getKey());
         pw.println(prefix + "  seen=" + mIsSeen);
         pw.println(prefix + "  groupKey=" + getGroupKey());
@@ -200,6 +260,9 @@
         pw.println(prefix + "  mPackageVisibility=" + mPackageVisibility);
         pw.println(prefix + "  mTopicImportance="
                 + NotificationListenerService.Ranking.importanceToString(mTopicImportance));
+        pw.println(prefix + "  mImportance="
+                + NotificationListenerService.Ranking.importanceToString(mImportance));
+        pw.println(prefix + "  mImportanceExplanation=" + mImportanceExplanation);
         pw.println(prefix + "  mIntercept=" + mIntercept);
         pw.println(prefix + "  mGlobalSortKey=" + mGlobalSortKey);
         pw.println(prefix + "  mRankingTimeMs=" + mRankingTimeMs);
@@ -234,15 +297,19 @@
     @Override
     public final String toString() {
         return String.format(
-                "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
+                "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s: %s)",
                 System.identityHashCode(this),
                 this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
-                this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(),
+                this.sbn.getTag(), this.mImportance, this.sbn.getKey(),
                 this.sbn.getNotification());
     }
 
     public void setContactAffinity(float contactAffinity) {
         mContactAffinity = contactAffinity;
+        if (mImportance < IMPORTANCE_DEFAULT &&
+                mContactAffinity > ValidateNotificationPeople.VALID_CONTACT) {
+            setImportance(IMPORTANCE_DEFAULT, getPeopleExplanation());
+        }
     }
 
     public float getContactAffinity() {
@@ -274,8 +341,30 @@
     }
 
     public void setTopicImportance(int importance) {
-        if (importance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
-            mTopicImportance = importance;
+        mTopicImportance = importance;
+        applyTopicImportance();
+    }
+
+    private String getTopicExplanation() {
+        if (mTopicExplanation == null) {
+            mTopicExplanation =
+                    mContext.getString(com.android.internal.R.string.importance_from_topic);
+        }
+        return mTopicExplanation;
+    }
+
+    private String getPeopleExplanation() {
+        if (mPeopleExplanation == null) {
+            mPeopleExplanation =
+                    mContext.getString(com.android.internal.R.string.importance_from_person);
+        }
+        return mPeopleExplanation;
+    }
+
+    private void applyTopicImportance() {
+        if (mTopicImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
+            mImportance = mTopicImportance;
+            mImportanceExplanation = getTopicExplanation();
         }
     }
 
@@ -283,6 +372,22 @@
         return mTopicImportance;
     }
 
+    public void setImportance(int importance, CharSequence explanation) {
+        if (importance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
+            mImportance = importance;
+            mImportanceExplanation = explanation;
+        }
+        applyTopicImportance();
+    }
+
+    public int getImportance() {
+        return mImportance;
+    }
+
+    public CharSequence getImportanceExplanation() {
+        return mImportanceExplanation;
+    }
+
     public boolean setIntercepted(boolean intercept) {
         mIntercept = intercept;
         return mIntercept;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 3c891df..6030bab 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -564,6 +564,7 @@
 
     private boolean evaluateZenMode(String reason, boolean setRingerMode) {
         if (DEBUG) Log.d(TAG, "evaluateZenMode");
+        final int zenBefore = mZenMode;
         final int zen = computeZenMode();
         ZenLog.traceSetZenMode(zen, reason);
         mZenMode = zen;
@@ -573,7 +574,7 @@
             applyZenToRingerMode();
         }
         applyRestrictions();
-        if (zen != mZenMode) {
+        if (zen != zenBefore) {
             mHandler.postDispatchOnZenModeChanged();
         }
         return true;
diff --git a/services/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java
index c0123bf..80faf473 100644
--- a/services/core/java/com/android/server/os/SchedulingPolicyService.java
+++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java
@@ -40,12 +40,13 @@
     public int requestPriority(int pid, int tid, int prio) {
         //Log.i(TAG, "requestPriority(pid=" + pid + ", tid=" + tid + ", prio=" + prio + ")");
 
-        // Verify that caller is mediaserver, priority is in range, and that the
-        // callback thread specified by app belongs to the app that called mediaserver.
-        // Once we've verified that the caller is mediaserver, we can trust the pid but
+        // Verify that the caller uid is permitted, priority is in range,
+        // and that the callback thread specified by app belongs to the app that
+        // called mediaserver or audioserver.
+        // Once we've verified that the caller uid is permitted, we can trust the pid but
         // we can't trust the tid.  No need to explicitly check for pid == 0 || tid == 0,
         // since if not the case then the getThreadGroupLeader() test will also fail.
-        if (Binder.getCallingUid() != Process.MEDIA_UID || prio < PRIORITY_MIN ||
+        if (!isPermittedCallingUid() || prio < PRIORITY_MIN ||
                 prio > PRIORITY_MAX || Process.getThreadGroupLeader(tid) != pid) {
             return PackageManager.PERMISSION_DENIED;
         }
@@ -61,4 +62,14 @@
         return PackageManager.PERMISSION_GRANTED;
     }
 
+    private boolean isPermittedCallingUid() {
+        final int callingUid = Binder.getCallingUid();
+        switch (callingUid) {
+        case Process.AUDIOSERVER_UID: // fastcapture, fastmixer
+        case Process.MEDIA_UID: // camera
+            return true;
+        default:
+            return false;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2f8157e..e0f85c5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -436,12 +436,6 @@
     final String[] mSeparateProcesses;
     final boolean mIsUpgrade;
 
-    // This is where all application persistent data goes.
-    final File mAppDataDir;
-
-    // This is where all application persistent data goes for secondary users.
-    final File mUserAppDataDir;
-
     /** The location for ASEC container files on internal storage. */
     final String mAsecInternalPath;
 
@@ -953,7 +947,7 @@
 
     // Recordkeeping of restore-after-install operations that are currently in flight
     // between the Package Manager and the Backup Manager
-    class PostInstallData {
+    static class PostInstallData {
         public InstallArgs args;
         public PackageInstalledInfo res;
 
@@ -1070,7 +1064,7 @@
                         }
                         long timeInMillis;
                         try {
-                            timeInMillis = Long.parseLong(timeInMillisString.toString());
+                            timeInMillis = Long.parseLong(timeInMillisString);
                         } catch (NumberFormatException e) {
                             throw new IOException("Failed to parse " + timeInMillisString
                                                   + " as a long.", e);
@@ -1987,12 +1981,10 @@
             Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
 
             File dataDir = Environment.getDataDirectory();
-            mAppDataDir = new File(dataDir, "data");
             mAppInstallDir = new File(dataDir, "app");
             mAppLib32InstallDir = new File(dataDir, "app-lib");
             mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
             mAsecInternalPath = new File(dataDir, "app-asec").getPath();
-            mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
 
             sUserManager = new UserManagerService(context, this, mPackages);
@@ -3368,14 +3360,6 @@
         }
     }
 
-    private void checkValidCaller(int uid, int userId) {
-        if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0)
-            return;
-
-        throw new SecurityException("Caller uid=" + uid
-                + " is not privileged to communicate with user=" + userId);
-    }
-
     @Override
     public int checkPermission(String permName, String pkgName, int userId) {
         if (!sUserManager.exists(userId)) {
@@ -4102,10 +4086,12 @@
         synchronized (mPackages) {
             if (mProtectedBroadcasts.contains(actionName)) {
                 return true;
-            } else if (actionName != null
-                    && actionName.startsWith("android.net.netmon.lingerExpired")) {
-                // TODO: remove this terrible hack
-                return true;
+            } else if (actionName != null) {
+                // TODO: remove these terrible hacks
+                if (actionName.startsWith("android.net.netmon.lingerExpired")
+                        || actionName.startsWith("com.android.server.sip.SipWakeupTimer")) {
+                    return true;
+                }
             }
         }
         return false;
@@ -9797,6 +9783,15 @@
             if (r1.system != r2.system) {
                 return r1.system ? -1 : 1;
             }
+            if (r1.activityInfo != null) {
+                return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName);
+            }
+            if (r1.serviceInfo != null) {
+                return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName);
+            }
+            if (r1.providerInfo != null) {
+                return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName);
+            }
             return 0;
         }
     };
@@ -10488,7 +10483,7 @@
             ArrayList<IntentFilter> result = new ArrayList<>();
             for (int n=0; n<count; n++) {
                 PackageParser.Activity activity = pkg.activities.get(n);
-                if (activity.intents != null || activity.intents.size() > 0) {
+                if (activity.intents != null && activity.intents.size() > 0) {
                     result.addAll(activity.intents);
                 }
             }
@@ -10907,7 +10902,7 @@
         }
     }
 
-    class MoveInfo {
+    static class MoveInfo {
         final int moveId;
         final String fromUuid;
         final String toUuid;
@@ -12213,7 +12208,7 @@
         }
     }
 
-    class PackageInstalledInfo {
+    static class PackageInstalledInfo {
         String name;
         int uid;
         // The set of users that originally had this package installed.
@@ -13154,10 +13149,6 @@
         }
     }
 
-    private static boolean isMultiArch(PackageSetting ps) {
-        return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
-    }
-
     private static boolean isMultiArch(ApplicationInfo info) {
         return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
     }
@@ -13170,10 +13161,6 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
-    private static boolean isExternal(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
-    }
-
     private static boolean isEphemeral(PackageParser.Package pkg) {
         return pkg.applicationInfo.isEphemeralApp();
     }
@@ -13857,7 +13844,7 @@
         return ret;
     }
 
-    private final class ClearStorageConnection implements ServiceConnection {
+    private final static class ClearStorageConnection implements ServiceConnection {
         IMediaContainerService mContainerService;
 
         @Override
@@ -15107,7 +15094,9 @@
                 // First, verify that this is a valid class name.
                 PackageParser.Package pkg = pkgSetting.pkg;
                 if (pkg == null || !pkg.hasComponentClassName(className)) {
-                    if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
+                    if (pkg != null &&
+                            pkg.applicationInfo.targetSdkVersion >=
+                                    Build.VERSION_CODES.JELLY_BEAN) {
                         throw new IllegalArgumentException("Component class " + className
                                 + " does not exist in " + packageName);
                     } else {
@@ -17317,7 +17306,7 @@
         }
     }
 
-    private final class OnPermissionChangeListeners extends Handler {
+    private final static class OnPermissionChangeListeners extends Handler {
         private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
 
         private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f9ed760..b18c846 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -103,11 +103,11 @@
                     return runUninstall();
                 case "resolve-activity":
                     return runResolveActivity();
-                case "query-intent-activities":
+                case "query-activities":
                     return runQueryIntentActivities();
-                case "query-intent-services":
+                case "query-services":
                     return runQueryIntentServices();
-                case "query-intent-receivers":
+                case "query-receivers":
                     return runQueryIntentReceivers();
                 default:
                     return handleDefaultCommands(cmd);
@@ -1043,13 +1043,13 @@
         pw.println("      -s: short summary");
         pw.println("      -d: only list dangerous permissions");
         pw.println("      -u: list only the permissions users will see");
-        pw.println("  resolve-intent [--user USER_ID] INTENT");
+        pw.println("  resolve-activity [--user USER_ID] INTENT");
         pw.println("    Prints the activity that resolves to the given Intent.");
-        pw.println("  query-intent-activities [--user USER_ID] INTENT");
+        pw.println("  query-activities [--user USER_ID] INTENT");
         pw.println("    Prints all activities that can handle the given Intent.");
-        pw.println("  query-intent-services [--user USER_ID] INTENT");
+        pw.println("  query-services [--user USER_ID] INTENT");
         pw.println("    Prints all services that can handle the given Intent.");
-        pw.println("  query-intent-receivers [--user USER_ID] INTENT");
+        pw.println("  query-receivers [--user USER_ID] INTENT");
         pw.println("    Prints all broadcast receivers that can handle the given Intent.");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 816903e..9bbc3c1 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -209,11 +209,13 @@
     }
 
     /**
-     * @return true if a restriction is settable by profile owner.
+     * @return true if a restriction is settable by profile owner.  Note it takes a user ID because
+     * some restrictions can be changed by PO only when it's running on the system user.
      */
-    public static boolean canProfileOwnerChange(String restriction) {
-        return !(IMMUTABLE_BY_OWNERS.contains(restriction)
-                || DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction));
+    public static boolean canProfileOwnerChange(String restriction, int userId) {
+        return !IMMUTABLE_BY_OWNERS.contains(restriction)
+                && !(userId != UserHandle.USER_SYSTEM
+                    && DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction));
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b9a9d6e..dff6e3f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3056,13 +3056,22 @@
             hideRecentApps(true, false);
         }
 
-        // Handle keyboard language switching.
+        // Handle keyboard layout switching.
+        // TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation.
+        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE
+                && ((metaState & KeyEvent.META_CTRL_MASK) != 0)) {
+            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+            return -1;
+        }
+
+        // Handle input method switching.
         if (down && repeatCount == 0
                 && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
                         || (keyCode == KeyEvent.KEYCODE_SPACE
-                                && (metaState & KeyEvent.META_CTRL_MASK) != 0))) {
-            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
-            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+                                && (metaState & KeyEvent.META_META_MASK) != 0))) {
+            final boolean forwardDirection = (metaState & KeyEvent.META_SHIFT_MASK) == 0;
+            mWindowManagerFuncs.switchInputMethod(forwardDirection);
             return -1;
         }
         if (mLanguageSwitchKeyPressed && !down
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 19b03d5..fc27170 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -216,12 +216,12 @@
     }
 
     @Override
-    public void expandSettingsPanel() {
+    public void expandSettingsPanel(String subPanel) {
         enforceExpandStatusBar();
 
         if (mBar != null) {
             try {
-                mBar.animateExpandSettingsPanel();
+                mBar.animateExpandSettingsPanel(subPanel);
             } catch (RemoteException ex) {
             }
         }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 4b6db99..d888c56 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,7 +53,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.service.trust.TrustAgentService;
 import android.util.ArraySet;
@@ -681,7 +680,9 @@
         public boolean isDeviceSecure(int userId) throws RemoteException {
             userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
-            userId = resolveProfileParent(userId);
+            if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+                userId = resolveProfileParent(userId);
+            }
 
             long token = Binder.clearCallingIdentity();
             try {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 97713fc..7be0ead 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -16,18 +16,35 @@
 
 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.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
 import android.os.Binder;
 import android.os.Process;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.util.AndroidRuntimeException;
 import android.util.Slog;
 import android.webkit.IWebViewUpdateService;
+import android.webkit.WebViewProviderInfo;
+import android.webkit.WebViewProviderResponse;
 import android.webkit.WebViewFactory;
 
 import com.android.server.SystemService;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
 /**
  * Private service to wait for the updatable WebView to be ready for use.
  * @hide
@@ -35,12 +52,23 @@
 public class WebViewUpdateService extends SystemService {
 
     private static final String TAG = "WebViewUpdateService";
-    private static final int WAIT_TIMEOUT_MS = 5000; // Same as KEY_DISPATCHING_TIMEOUT.
+    private static final int WAIT_TIMEOUT_MS = 4500; // KEY_DISPATCHING_TIMEOUT is 5000.
 
-    private boolean mRelroReady32Bit = false;
-    private boolean mRelroReady64Bit = false;
+    // Keeps track of the number of running relro creations
+    private int mNumRelroCreationsStarted = 0;
+    private int mNumRelroCreationsFinished = 0;
+    // Implies that we need to rerun relro creation because we are using an out-of-date package
+    private boolean mWebViewPackageDirty = false;
+    // Set to true when the current provider is being replaced
+    private boolean mCurrentProviderBeingReplaced = false;
+    private boolean mAnyWebViewInstalled = false;
 
-    private String oldWebViewPackageName = null;
+    private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
+
+    // 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;
 
@@ -53,28 +81,69 @@
         mWebViewUpdatedReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-
-                    // When a package is replaced we will receive two intents, one representing the
-                    // removal of the old package and one representing the addition of the new
-                    // package. We here ignore the intent representing the removed package to make
-                    // sure we don't change WebView provider twice.
+                    // When a package is replaced we will receive two intents, one representing
+                    // the removal of the old package and one representing the addition of the
+                    // new package.
+                    // In the case where we receive an intent to remove the old version of the
+                    // package that is being replaced we set a flag here and early-out so that we
+                    // don't change provider while replacing the current package (we will instead
+                    // change provider when the new version of the package is being installed).
                     if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
-                            && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
+                        && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
+                        synchronized(this) {
+                            if (mCurrentWebViewPackage == null) return;
+
+                            String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
+                            if (webViewPackage.equals(intent.getDataString()))
+                                mCurrentProviderBeingReplaced = true;
+                        }
+
                         return;
                     }
 
-                    for (String packageName : WebViewFactory.getWebViewPackageNames()) {
-                        String webviewPackage = "package:" + packageName;
+                    for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+                        String webviewPackage = "package:" + provider.packageName;
 
                         if (webviewPackage.equals(intent.getDataString())) {
-                            String usedPackageName =
-                                WebViewFactory.findPreferredWebViewPackage().packageName;
-                            // Only trigger update actions if the updated package is the one that
-                            // will be used, or the one that was in use before the update.
-                            if (packageName.equals(usedPackageName) ||
-                                    packageName.equals(oldWebViewPackageName)) {
-                                onWebViewUpdateInstalled();
-                                oldWebViewPackageName = usedPackageName;
+                            boolean updateWebView = false;
+                            boolean removedOldPackage = false;
+                            String oldProviderName = null;
+                            PackageInfo newPackage = null;
+                            synchronized(WebViewUpdateService.this) {
+                                try {
+                                    updateValidWebViewPackages();
+                                    newPackage = findPreferredWebViewPackage();
+                                    if (mCurrentWebViewPackage != null)
+                                        oldProviderName = mCurrentWebViewPackage.packageName;
+                                    // Only trigger update actions if the updated package is the one
+                                    // that will be used, or the one that was in use before the
+                                    // update, or if we haven't seen a valid WebView package before.
+                                    updateWebView =
+                                        provider.packageName.equals(newPackage.packageName)
+                                        || provider.packageName.equals(oldProviderName)
+                                        || mCurrentWebViewPackage == null;
+                                    // We removed the old package if we received an intent to remove
+                                    // or replace the old package.
+                                    removedOldPackage =
+                                        provider.packageName.equals(oldProviderName);
+                                    if (updateWebView) {
+                                        onWebViewProviderChanged(newPackage);
+                                    }
+                                } catch (WebViewFactory.MissingWebViewPackageException e) {
+                                    Slog.e(TAG, "Could not find valid WebView package to create " +
+                                            "relro with " + e);
+                                }
+                            }
+                            if(updateWebView && !removedOldPackage && oldProviderName != null) {
+                                // If the provider change is the result of adding or replacing a
+                                // 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.
+                                try {
+                                    ActivityManagerNative.getDefault().killPackageDependents(
+                                        oldProviderName, getContext().getUserId());
+                                } catch (RemoteException e) {
+                                }
                             }
                             return;
                         }
@@ -90,14 +159,182 @@
         publishBinderService("webviewupdate", new BinderService());
     }
 
-    private void onWebViewUpdateInstalled() {
-        Slog.d(TAG, "WebView Package updated!");
-
-        synchronized (this) {
-            mRelroReady32Bit = false;
-            mRelroReady64Bit = false;
+    /**
+     * Perform any WebView loading preparations that must happen at boot from the system server,
+     * after the package manager has started or after an update to the webview is installed.
+     * This must be called in the system server.
+     * Currently, this means spawning the child processes which will create the relro files.
+     */
+    public void prepareWebViewInSystemServer() {
+        try {
+            synchronized(this) {
+                updateValidWebViewPackages();
+                mCurrentWebViewPackage = findPreferredWebViewPackage();
+                onWebViewProviderChanged(mCurrentWebViewPackage);
+            }
+        } catch (Throwable t) {
+            // Log and discard errors at this stage as we must not crash the system server.
+            Slog.e(TAG, "error preparing webview provider from system server", t);
         }
-        WebViewFactory.onWebViewUpdateInstalled();
+    }
+
+
+    /**
+     * Change WebView provider and provider setting and kill packages using the old provider.
+     */
+    private void changeProviderAndSetting(String newProviderName) {
+        PackageInfo oldPackage = null;
+        PackageInfo newPackage = null;
+        synchronized(this) {
+            oldPackage = mCurrentWebViewPackage;
+            updateUserSetting(newProviderName);
+
+            try {
+                newPackage = findPreferredWebViewPackage();
+                if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
+                    // If we don't perform the user change, revert the settings change.
+                    updateUserSetting(newPackage.packageName);
+                    return;
+                }
+            } catch (WebViewFactory.MissingWebViewPackageException e) {
+                Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
+                        + e);
+                // If we don't perform the user change but don't have an installed WebView package,
+                // we will have changed the setting and it will be used when a package is available.
+                return;
+            }
+            onWebViewProviderChanged(newPackage);
+        }
+        // Kill apps using the old provider
+        try {
+            if (oldPackage != null) {
+                ActivityManagerNative.getDefault().killPackageDependents(
+                        oldPackage.packageName, getContext().getUserId());
+            }
+        } catch (RemoteException e) {
+        }
+        return;
+    }
+
+    /**
+     * This is called when we change WebView provider, either when the current provider is updated
+     * or a new provider is chosen / takes precedence.
+     */
+    private void onWebViewProviderChanged(PackageInfo newPackage) {
+        synchronized(this) {
+            mAnyWebViewInstalled = true;
+            // If we have changed provider then the replacement of the old provider is
+            // irrelevant - we can only have chosen a new provider if its package is available.
+            mCurrentProviderBeingReplaced = false;
+            if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
+                mCurrentWebViewPackage = newPackage;
+                updateUserSetting(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 = WebViewFactory.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();
+            } else {
+                mWebViewPackageDirty = true;
+            }
+        }
+    }
+
+    /**
+     * 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(WebViewFactory.getWebViewPackages()));
+        Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
+        // remove non-valid packages
+        while(it.hasNext()) {
+            WebViewProviderInfo current = it.next();
+            if (!current.isValidProvider())
+                it.remove();
+        }
+        synchronized(this) {
+            mCurrentValidWebViewPackages =
+                webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+        }
+    }
+
+    private static String getUserChosenWebViewProvider() {
+        return Settings.Secure.getString(AppGlobals.getInitialApplication().getContentResolver(),
+                Settings.Secure.WEBVIEW_PROVIDER);
+    }
+
+    private void updateUserSetting(String newProviderName) {
+        Settings.Secure.putString(getContext().getContentResolver(),
+                Settings.Secure.WEBVIEW_PROVIDER,
+                newProviderName == null ? "" : newProviderName);
+    }
+
+    /**
+     * Returns either the package info of the WebView provider determined in the following way:
+     * If the user has chosen a provider then use that if it is valid,
+     * otherwise use the first package in the webview priority list that is valid.
+     *
+     * @hide
+     */
+    private PackageInfo findPreferredWebViewPackage() {
+        WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
+
+        String userChosenProvider = getUserChosenWebViewProvider();
+
+        // If the user has chosen provider, use that
+        for (WebViewProviderInfo provider : providers) {
+            if (provider.packageName.equals(userChosenProvider)) {
+                return provider.getPackageInfo();
+            }
+        }
+
+        // User did not choose, or the choice failed, use the most stable provider available
+        for (WebViewProviderInfo provider : providers) {
+            return provider.getPackageInfo();
+        }
+        mAnyWebViewInstalled = false;
+        throw new WebViewFactory.MissingWebViewPackageException(
+                "Could not find a loadable WebView package");
+    }
+
+    /**
+     * Returns whether WebView is ready and is not going to go through its preparation phase again
+     * directly.
+     */
+    private boolean webViewIsReadyLocked() {
+        return !mWebViewPackageDirty
+            && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
+            && !mCurrentProviderBeingReplaced
+            // The current package might be replaced though we haven't received an intent declaring
+            // this yet, the following flag makes anyone loading WebView to wait in this case.
+            && mAnyWebViewInstalled;
+    }
+
+    private void checkIfRelrosDoneLocked() {
+        if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
+            if (mWebViewPackageDirty) {
+                mWebViewPackageDirty = false;
+                // If we have changed provider since we started the relro creation we need to
+                // redo the whole process using the new package instead.
+                // Though, if the current provider package is being replaced we don't want to change
+                // provider here since we will perform the change either when the package is added
+                // again or when we switch to another provider (whichever comes first).
+                if (!mCurrentProviderBeingReplaced) {
+                    PackageInfo newPackage = findPreferredWebViewPackage();
+                    onWebViewProviderChanged(newPackage);
+                }
+            } else {
+                this.notifyAll();
+            }
+        }
     }
 
     private class BinderService extends IWebViewUpdateService.Stub {
@@ -108,7 +345,7 @@
          * crashed.
          */
         @Override // Binder call
-        public void notifyRelroCreationCompleted(boolean is64Bit, boolean success) {
+        public void notifyRelroCreationCompleted() {
             // Verify that the caller is either the shared relro process (nominal case) or the
             // system server (only in the case the relro process crashes and we get here via the
             // crashHandler).
@@ -118,20 +355,17 @@
             }
 
             synchronized (WebViewUpdateService.this) {
-                if (is64Bit) {
-                    mRelroReady64Bit = true;
-                } else {
-                    mRelroReady32Bit = true;
-                }
-                WebViewUpdateService.this.notifyAll();
+                mNumRelroCreationsFinished++;
+                checkIfRelrosDoneLocked();
             }
         }
 
         /**
          * WebViewFactory calls this to block WebView loading until the relro file is created.
+         * Returns the WebView provider for which we create relro files.
          */
         @Override // Binder call
-        public void waitForRelroCreationCompleted(boolean is64Bit) {
+        public WebViewProviderResponse waitForAndGetProvider() {
             // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
             // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
             // another service there tries to bring up a WebView in the between, the wait below
@@ -140,21 +374,74 @@
                 throw new IllegalStateException("Cannot create a WebView from the SystemServer");
             }
 
+            PackageInfo webViewPackage = null;
             final long NS_PER_MS = 1000000;
             final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
-            boolean relroReady = (is64Bit ? mRelroReady64Bit : mRelroReady32Bit);
+            boolean webViewReady = false;
+            int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
             synchronized (WebViewUpdateService.this) {
-                while (!relroReady) {
+                webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
+                while (!webViewReady) {
                     final long timeNowMs = System.nanoTime() / NS_PER_MS;
                     if (timeNowMs >= timeoutTimeMs) break;
                     try {
                         WebViewUpdateService.this.wait(timeoutTimeMs - timeNowMs);
                     } catch (InterruptedException e) {}
-                    relroReady = (is64Bit ? mRelroReady64Bit : mRelroReady32Bit);
+                    webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
+                }
+                // Make sure we return the provider that was used to create the relro file
+                webViewPackage = WebViewUpdateService.this.mCurrentWebViewPackage;
+                if (webViewReady) {
+                } else if (mCurrentProviderBeingReplaced) {
+                    // It is important that we check this flag before the one representing WebView
+                    // being installed, otherwise we might think there is no WebView though the
+                    // current one is just being replaced.
+                    webViewStatus = WebViewFactory.LIBLOAD_WEBVIEW_BEING_REPLACED;
+                } else if (!mAnyWebViewInstalled) {
+                    webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
+                } else {
+                    // Either the current relro creation  isn't done yet, or the new relro creatioin
+                    // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
+                    webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
                 }
             }
-            if (!relroReady) Slog.w(TAG, "creating relro file timed out");
+            if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
+            return new WebViewProviderResponse(webViewPackage, webViewStatus);
+        }
+
+        /**
+         * This is called from DeveloperSettings when the user changes WebView provider.
+         */
+        @Override // Binder call
+        public void changeProviderAndSetting(String newProvider) {
+            if (getContext().checkCallingPermission(
+                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                String msg = "Permission Denial: changeProviderAndSetting() from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid()
+                        + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+
+            WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+        }
+
+        @Override // Binder call
+        public WebViewProviderInfo[] getValidWebViewPackages() {
+            synchronized(WebViewUpdateService.this) {
+                return mCurrentValidWebViewPackages;
+            }
+        }
+
+        @Override // Binder call
+        public String getCurrentWebViewPackageName() {
+            synchronized(WebViewUpdateService.this) {
+                if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
+                    return null;
+                return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
+            }
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index fd5c704..b49641f 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -122,21 +123,6 @@
     // True if the windows associated with this token should be cropped to their stack bounds.
     boolean mCropWindowsToStack;
 
-    // This application will have its window replaced due to relaunch. This allows window manager
-    // to differentiate between simple removal of a window and replacement. In the latter case it
-    // will preserve the old window until the new one is drawn.
-    boolean mWillReplaceWindow;
-    // If true, the replaced window was already requested to be removed.
-    boolean mReplacingRemoveRequested;
-    // Whether the replacement of the window should trigger app transition animation.
-    boolean mAnimateReplacingWindow;
-    // If not null, the window that will be used to replace the old one. This is being set when
-    // the window is added and unset when this window reports its first draw.
-    WindowState mReplacingWindow;
-    // Whether the new window has replaced the old one, so the old one can be removed without
-    // blinking.
-    boolean mHasReplacedWindow;
-
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
             boolean _voiceInteraction) {
         super(_service, _token.asBinder(),
@@ -392,6 +378,62 @@
         }
     }
 
+    void setReplacingWindows(boolean animate) {
+        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
+                + " with replacing windows.");
+
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            w.setReplacing(animate);
+        }
+        if (animate) {
+            // Set-up dummy animation so we can start treating windows associated with this
+            // token like they are in transition before the new app window is ready for us to
+            // run the real transition animation.
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+                    "setReplacingWindow() Setting dummy animation on: " + this);
+            mAppAnimator.setDummyAnimation();
+        }
+    }
+
+    void addWindow(WindowState w) {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            WindowState candidate = allAppWindows.get(i);
+            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
+                    candidate.getWindowTag().equals(w.getWindowTag().toString())) {
+                candidate.mReplacingWindow = w;
+            }
+        }
+        allAppWindows.add(w);
+    }
+
+    boolean waitingForReplacement() {
+        for (int i = allAppWindows.size() -1; i >= 0; i--) {
+            WindowState candidate = allAppWindows.get(i);
+            if (candidate.mWillReplaceWindow) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void clearTimedoutReplaceesLocked() {
+        for (int i = allAppWindows.size() - 1; i >= 0;
+             // removeWindowLocked at bottom of loop may remove multiple entries from
+             // allAppWindows if the window to be removed has child windows. It also may
+             // not remove any windows from allAppWindows at all if win is exiting and
+             // currently animating away. This ensures that winNdx is monotonically decreasing
+             // and never beyond allAppWindows bounds.
+             i = Math.min(i - 1, allAppWindows.size() - 1)) {
+            WindowState candidate = allAppWindows.get(i);
+            if (candidate.mWillReplaceWindow == false) {
+                continue;
+            }
+            candidate.mWillReplaceWindow = false;
+            service.removeWindowLocked(candidate);
+        }
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9b64481..5942198 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -110,6 +110,8 @@
 
     final DimLayerController mDimLayerController;
 
+    final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
+
     /**
      * @param display May not be null.
      * @param service You know.
@@ -412,6 +414,11 @@
             inputMethod.getTouchableRegion(mTmpRegion);
             mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
         }
+        for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
+            WindowState win = mTapExcludedWindows.get(i);
+            win.getTouchableRegion(mTmpRegion);
+            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
+        }
         if (mTapDetector != null) {
             mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion, mNonResizeableRegion);
         }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 49d9efe..b961879 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -144,6 +144,14 @@
         return true;
     }
 
+    boolean isFullscreenBounds(Rect bounds) {
+        if (mDisplayContent == null || bounds == null) {
+            return true;
+        }
+        mDisplayContent.getLogicalDisplayRect(mTmpRect);
+        return mTmpRect.equals(bounds);
+    }
+
     private boolean setBounds(Rect bounds) {
         boolean oldFullscreen = mFullscreen;
         int rotation = Surface.ROTATION_0;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 3db9ae0..2e424d0 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -506,7 +506,7 @@
                 inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
             }
 
-            replacing = replacing || (w.mAppToken != null && w.mAppToken.mWillReplaceWindow);
+            replacing = replacing || w.mWillReplaceWindow;
 
             // If the app is executing an animation because the keyguard is going away,
             // keep the wallpaper during the animation so it doesn't flicker out.
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index a6523a4..6a5183f 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -918,10 +918,6 @@
     }
 
     void requestRemovalOfReplacedWindows(WindowState win) {
-        final AppWindowToken token = win.mAppToken;
-        if (token != null && token.mWillReplaceWindow && token.mReplacingWindow == win) {
-            token.mHasReplacedWindow = true;
-        }
         mRemoveReplacedWindows = true;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index a49bb31..845100d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -36,7 +36,7 @@
     static final boolean DEBUG_RESIZE = false;
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
-    static final boolean DEBUG_FOCUS = false;
+    static final boolean DEBUG_FOCUS = true;
     static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
     static final boolean DEBUG_ANIM = false;
     static final boolean DEBUG_KEYGUARD = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dbbbb58..456c416 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -42,6 +42,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
@@ -185,6 +186,7 @@
 import android.view.WindowManagerPolicy;
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
+import android.view.inputmethod.InputMethodManagerInternal;
 import android.widget.Toast;
 
 import com.android.internal.R;
@@ -267,6 +269,9 @@
     /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
     static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
 
+    /** Amount of time (in milliseconds) to delay before declaring a window replacement timeout. */
+    static final int WINDOW_REPLACEMENT_TIMEOUT_DURATION = 2000;
+
     /** Amount of time to allow a last ANR message to exist before freeing the memory. */
     static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours
     /**
@@ -457,7 +462,6 @@
     EmulatorDisplayOverlay mEmulatorDisplayOverlay;
 
     final float[] mTmpFloats = new float[9];
-    final Rect mTmpContentRect = new Rect();
 
     boolean mDisplayReady;
     boolean mSafeMode;
@@ -1349,10 +1353,7 @@
         final AppWindowToken appToken = win.mAppToken;
         if (appToken != null) {
             if (addToToken) {
-                appToken.allAppWindows.add(win);
-            }
-            if (appToken.mWillReplaceWindow) {
-                appToken.mReplacingWindow = win;
+                appToken.addWindow(win);
             }
         }
     }
@@ -1966,6 +1967,10 @@
 
             res = WindowManagerGlobal.ADD_OKAY;
 
+            if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+                displayContent.mTapExcludedWindows.add(win);
+            }
+
             origId = Binder.clearCallingIdentity();
 
             if (addToken) {
@@ -2083,14 +2088,15 @@
     }
 
     private void prepareWindowReplacementTransition(AppWindowToken atoken) {
-        if (atoken == null || !atoken.mWillReplaceWindow || !atoken.mAnimateReplacingWindow) {
+        if (atoken == null) {
             return;
         }
         atoken.allDrawn = false;
         WindowState replacedWindow = null;
         for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) {
             WindowState candidate = atoken.windows.get(i);
-            if (candidate.mExiting) {
+            if (candidate.mExiting && candidate.mWillReplaceWindow
+                    && candidate.mAnimateReplacingWindow) {
                 replacedWindow = candidate;
             }
         }
@@ -2190,7 +2196,7 @@
                 + " app-animation="
                 + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
                 + " mWillReplaceWindow="
-                + (win.mAppToken != null ? win.mAppToken.mWillReplaceWindow : false)
+                + win.mWillReplaceWindow
                 + " inPendingTransaction="
                 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
                 + " mDisplayFrozen=" + mDisplayFrozen);
@@ -2202,13 +2208,13 @@
         // animation wouldn't be seen.
         if (win.mHasSurface && okToDisplay()) {
             final AppWindowToken appToken = win.mAppToken;
-            if (appToken != null && appToken.mWillReplaceWindow) {
+            if (win.mWillReplaceWindow) {
                 // This window is going to be replaced. We need to keep it around until the new one
                 // gets added, then we will get rid of this one.
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Preserving " + win + " until the new one is "
                         + "added");
                 win.mExiting = true;
-                appToken.mReplacingRemoveRequested = true;
+                win.mReplacingRemoveRequested = true;
                 Binder.restoreCallingIdentity(origId);
                 return;
             }
@@ -2309,6 +2315,11 @@
             Slog.w(TAG_WM, "Removing window " + win, e);
         }
 
+        final int type = win.mAttrs.type;
+        if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+            final DisplayContent displaycontent = win.getDisplayContent();
+            displaycontent.mTapExcludedWindows.remove(win);
+        }
         mPolicy.removeWindowLw(win);
         win.removeLocked();
 
@@ -2364,7 +2375,7 @@
             }
         }
 
-        if (win.mAttrs.type == TYPE_WALLPAPER) {
+        if (type == TYPE_WALLPAPER) {
             mWallpaperControllerLocked.clearLastWallpaperTimeoutTime();
             getDefaultDisplayContentLocked().pendingLayoutChanges |=
                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -2534,26 +2545,32 @@
                 win.mAttrs.height = bottom - top;
                 win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
 
-                if (SHOW_TRANSACTIONS) {
-                    Slog.i(TAG_WM, ">>> OPEN TRANSACTION repositionChild");
-                }
+                if (win.mHasSurface) {
+                    if (SHOW_TRANSACTIONS) {
+                        Slog.i(TAG_WM, ">>> OPEN TRANSACTION repositionChild");
+                    }
 
-                SurfaceControl.openTransaction();
+                    SurfaceControl.openTransaction();
 
-                win.applyGravityAndUpdateFrame();
-                win.mWinAnimator.computeShownFrameLocked();
+                    try {
 
-                win.mWinAnimator.setSurfaceBoundariesLocked(false);
+                        win.applyGravityAndUpdateFrame();
+                        win.mWinAnimator.computeShownFrameLocked();
 
-                if (deferTransactionUntilFrame > 0) {
-                    win.mWinAnimator.mSurfaceController.deferTransactionUntil(
-                            win.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
-                            deferTransactionUntilFrame);
-                }
+                        win.mWinAnimator.setSurfaceBoundariesLocked(false);
 
-                SurfaceControl.closeTransaction();
-                if (SHOW_TRANSACTIONS) {
-                    Slog.i(TAG_WM, "<<< CLOSE TRANSACTION repositionChild");
+                        if (deferTransactionUntilFrame > 0) {
+                            win.mWinAnimator.mSurfaceController.deferTransactionUntil(
+                                    win.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
+                                    deferTransactionUntilFrame);
+                        }
+
+                    } finally {
+                        SurfaceControl.closeTransaction();
+                        if (SHOW_TRANSACTIONS) {
+                            Slog.i(TAG_WM, "<<< CLOSE TRANSACTION repositionChild");
+                        }
+                    }
                 }
 
                 outFrame = win.mCompatFrame;
@@ -4036,7 +4053,7 @@
         // transition animation
         // * or this is an opening app and windows are being replaced.
         if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting) ||
-                (visible && wtoken.mWillReplaceWindow)) {
+                (visible && wtoken.waitingForReplacement())) {
             boolean changed = false;
             if (DEBUG_APP_TRANSITIONS) Slog.v(
                 TAG_WM, "Changing app " + wtoken + " hidden=" + wtoken.hidden
@@ -4813,6 +4830,17 @@
         }
     }
 
+    /** Returns true if the input bounds corresponds to the fullscreen bounds the stack is on. */
+    public boolean isFullscreenBounds(int stackId, Rect bounds) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null || bounds == null) {
+                return true;
+            }
+            return stack.isFullscreenBounds(bounds);
+        }
+    }
+
     /**
      * Re-sizes a stack and its containing tasks.
      * @param stackId Id of stack to resize.
@@ -5281,6 +5309,16 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
+    public void switchInputMethod(boolean forwardDirection) {
+        final InputMethodManagerInternal inputMethodManagerInternal =
+                LocalServices.getService(InputMethodManagerInternal.class);
+        if (inputMethodManagerInternal != null) {
+            inputMethodManagerInternal.switchInputMethod(forwardDirection);
+        }
+    }
+
+    // Called by window manager policy.  Not exposed externally.
+    @Override
     public void shutdown(boolean confirm) {
         ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
     }
@@ -7477,6 +7515,8 @@
         public static final int TWO_FINGER_SCROLL_START = 45;
         public static final int SHOW_NON_RESIZEABLE_DOCK_TOAST = 46;
 
+        public static final int WINDOW_REPLACEMENT_TIMEOUT = 47;
+
         /**
          * Used to denote that an integer field in a message will not be used.
          */
@@ -8059,6 +8099,13 @@
                     toast.show();
                 }
                 break;
+                case WINDOW_REPLACEMENT_TIMEOUT: {
+                    final AppWindowToken token = (AppWindowToken) msg.obj;
+                    synchronized (mWindowMap) {
+                        token.clearTimedoutReplaceesLocked();
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
@@ -8581,7 +8628,7 @@
                 final int numTokens = tokens.size();
                 for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (wtoken.mIsExiting && !wtoken.mWillReplaceWindow) {
+                    if (wtoken.mIsExiting && !wtoken.waitingForReplacement()) {
                         continue;
                     }
                     i = reAddAppWindowsLocked(displayContent, i, wtoken);
@@ -8690,8 +8737,8 @@
     private void forceHigherLayerIfNeeded(WindowState w, WindowStateAnimator winAnimator,
             AppWindowToken wtoken) {
         boolean force = false;
-        if (wtoken.mWillReplaceWindow && wtoken.mReplacingWindow != w
-                && wtoken.mAnimateReplacingWindow) {
+
+        if (w.mWillReplaceWindow) {
             // 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.
@@ -10207,26 +10254,20 @@
      * @param token Application token for which the activity will be relaunched.
      */
     public void setReplacingWindow(IBinder token, boolean animate) {
+        AppWindowToken appWindowToken = null;
         synchronized (mWindowMap) {
-            AppWindowToken appWindowToken = findAppWindowToken(token);
+            appWindowToken = findAppWindowToken(token);
             if (appWindowToken == null || !appWindowToken.isVisible()) {
                 Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
                 return;
             }
-            if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
-                    + " as replacing window.");
-            appWindowToken.mWillReplaceWindow = true;
-            appWindowToken.mHasReplacedWindow = false;
-            appWindowToken.mAnimateReplacingWindow = animate;
+            appWindowToken.setReplacingWindows(animate);
+        }
 
-            if (animate) {
-                // Set-up dummy animation so we can start treating windows associated with this
-                // token like they are in transition before the new app window is ready for us to
-                // run the real transition animation.
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
-                        "setReplacingWindow() Setting dummy animation on: " + appWindowToken);
-                appWindowToken.mAppAnimator.setDummyAnimation();
-            }
+        if (appWindowToken != null) {
+            mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+            mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
+                    WINDOW_REPLACEMENT_TIMEOUT_DURATION);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0fc7142..e4a6806 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -75,6 +75,7 @@
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -403,6 +404,18 @@
     // used to start an entering animation earlier.
     public boolean mSurfaceSaved = false;
 
+    // This window will be replaced due to relaunch. This allows window manager
+    // to differentiate between simple removal of a window and replacement. In the latter case it
+    // will preserve the old window until the new one is drawn.
+    boolean mWillReplaceWindow = false;
+    // If true, the replaced window was already requested to be removed.
+    boolean mReplacingRemoveRequested = false;
+    // Whether the replacement of the window should trigger app transition animation.
+    boolean mAnimateReplacingWindow = false;
+    // If not null, the window that will be used to replace the old one. This is being set when
+    // the window is added and unset when this window reports its first draw.
+    WindowState mReplacingWindow = null;
+
     /**
      * Wake lock for drawing.
      * Even though it's slightly more expensive to do so, we will use a separate wake lock
@@ -521,7 +534,7 @@
         }
 
         WindowState appWin = this;
-        while (appWin.mAttachedWindow != null) {
+        while (appWin.isChildWindow()) {
             appWin = appWin.mAttachedWindow;
         }
         WindowToken appToken = appWin.mToken;
@@ -580,8 +593,7 @@
     @Override
     public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
             Rect osf) {
-        if (mAppToken != null && mAppToken.mWillReplaceWindow
-                && (mExiting || !mAppToken.mReplacingRemoveRequested)) {
+        if (mWillReplaceWindow && (mExiting || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
             // want to apply any more changes to it, so it remains in this state until new window
@@ -854,7 +866,7 @@
     @Override
     public int getBaseType() {
         WindowState win = this;
-        while (win.mAttachedWindow != null) {
+        while (win.isChildWindow()) {
             win = win.mAttachedWindow;
         }
         return win.mAttrs.type;
@@ -1235,7 +1247,7 @@
     void removeLocked() {
         disposeInputChannel();
 
-        if (mAttachedWindow != null) {
+        if (isChildWindow()) {
             if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + this + " from " + mAttachedWindow);
             mAttachedWindow.mChildWindows.remove(this);
         }
@@ -1343,17 +1355,17 @@
     }
 
     void maybeRemoveReplacedWindow() {
-        AppWindowToken token = mAppToken;
-        if (token != null && token.mWillReplaceWindow && token.mReplacingWindow == this
-                && token.mHasReplacedWindow) {
-            if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replacing window: " + this);
-            token.mWillReplaceWindow = false;
-            token.mAnimateReplacingWindow = false;
-            token.mReplacingRemoveRequested = false;
-            token.mReplacingWindow = null;
-            token.mHasReplacedWindow = false;
-            for (int i = token.allAppWindows.size() - 1; i >= 0; i--) {
-                final WindowState win = token.allAppWindows.get(i);
+        if (mAppToken == null) {
+            return;
+        }
+        for (int i = mAppToken.allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState win = mAppToken.allAppWindows.get(i);
+            if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + win);
+            if (win.mWillReplaceWindow && win.mReplacingWindow == this) {
+                win.mWillReplaceWindow = false;
+                win.mAnimateReplacingWindow = false;
+                win.mReplacingRemoveRequested = false;
+                win.mReplacingWindow = null;
                 if (win.mExiting) {
                     mService.removeWindowInnerLocked(win);
                 }
@@ -1682,7 +1694,7 @@
             // first frame very fast. Saving surfaces are mostly a waste of memory.
             // Don't save if the window is not the topmost window.
             mSurfaceSaved = false;
-        } else if (mAttachedWindow != null) {
+        } else if (isChildWindow()) {
             mSurfaceSaved = false;
         } else {
             mSurfaceSaved = mAppToken.shouldSaveSurface();
@@ -1733,7 +1745,7 @@
     boolean isHiddenFromUserLocked() {
         // Attached windows are evaluated based on the window that they are attached to.
         WindowState win = this;
-        while (win.mAttachedWindow != null) {
+        while (win.isChildWindow()) {
             win = win.mAttachedWindow;
         }
         if (win.mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
@@ -1997,7 +2009,7 @@
             pw.print(prefix); pw.print("LastRequested w="); pw.print(mLastRequestedWidth);
                     pw.print(" h="); pw.println(mLastRequestedHeight);
         }
-        if (mAttachedWindow != null || mLayoutAttached) {
+        if (isChildWindow() || mLayoutAttached) {
             pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
                     pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
         }
@@ -2161,7 +2173,7 @@
             + " " + getWindowTag();
     }
 
-    private CharSequence getWindowTag() {
+    CharSequence getWindowTag() {
         CharSequence tag = mAttrs.getTitle();
         if (tag == null || tag.length() <= 0) {
             tag = mAttrs.packageName;
@@ -2255,4 +2267,16 @@
         // Now make sure the window fits in the overall display frame.
         Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
     }
+
+    boolean isChildWindow() {
+        return mAttachedWindow != null;
+    }
+
+    void setReplacing(boolean animate) {
+        if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) == 0) {
+            mWillReplaceWindow = true;
+            mReplacingWindow = null;
+            mAnimateReplacingWindow = animate;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 7cd67d0..d4001cd 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -710,11 +710,13 @@
 
         // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
         if (mTmpSize.width() < 1) {
-            Slog.w(TAG, "Width of " + w + " is not positive " + mTmpSize.width());
+            if (!mWin.mLayoutNeeded) Slog.w(TAG,
+                    "Width of " + w + " is not positive " + mTmpSize.width());
             mTmpSize.right = mTmpSize.left + 1;
         }
         if (mTmpSize.height() < 1) {
-            Slog.w(TAG, "Height of " + w + " is not positive " + mTmpSize.height());
+            if (!mWin.mLayoutNeeded) Slog.w(TAG,
+                    "Height of " + w + " is not positive " + mTmpSize.height());
             mTmpSize.bottom = mTmpSize.top + 1;
         }
 
@@ -1135,17 +1137,19 @@
         final boolean isFreeformResizing =
                 w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
         final Rect clipRect = mTmpClipRect;
-        if (isFreeformResizing) {
-            // When we're doing a drag-resizing, the surface is set up to cover full screen.
-            // Set the clip rect to be the same size so that we don't get any scaling.
-            clipRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-        } else {
-            // We use the clip rect as provided by the tranformation for non-fullscreen windows to
-            // avoid premature clipping with the system decor rect.
-            clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
-            if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect="
-                    + mHasClipRect + ", fullscreen=" + fullscreen);
+
+        // We use the clip rect as provided by the tranformation for non-fullscreen windows to
+        // avoid premature clipping with the system decor rect.
+        clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect="
+                + mHasClipRect + ", fullscreen=" + fullscreen);
+
+        if (isFreeformResizing && !w.isChildWindow()) {
+            // For freeform resizing non child windows, we are using the big surface positioned
+            // at 0,0. Thus we must express the crop in that coordinate space.
+            clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
         }
+
         // Expand the clip rect for surface insets.
         final WindowManager.LayoutParams attrs = w.mAttrs;
         clipRect.left -= attrs.surfaceInsets.left;
@@ -1188,7 +1192,7 @@
         // different stack. If we suddenly crop it to the new stack bounds, it might get cut off.
         // We don't want it to happen, so we let it ignore the stack bounds until it gets removed.
         // The window that will replace it will abide them.
-        if (isAnimating() && (appToken.mWillReplaceWindow || w.inDockedWorkspace()
+        if (isAnimating() && (w.mWillReplaceWindow || w.inDockedWorkspace()
                 || w.inFreeformWorkspace())) {
             return;
         }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index bd2912d..9675d2f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -131,13 +131,9 @@
     }
 
     void destroyInTransaction() {
-        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-            RuntimeException e = null;
-            if (!HIDE_STACK_CRAWLS) {
-                e = new RuntimeException();
-                e.fillInStackTrace();
-            }
-        }
+        //        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(3));
+        //        }
         try {
             mSurfaceControl.destroy();
             mSurfaceShown = false;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 50bdf25..160c97f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -96,6 +96,7 @@
     private long mUserActivityTimeout = -1;
     private boolean mUpdateRotation = false;
     private final Rect mTmpStartRect = new Rect();
+    private final Rect mTmpContentRect = new Rect();
 
     // Set to true when the display contains content to show the user.
     // When false, the display manager may choose to mirror or blank the display.
@@ -862,8 +863,8 @@
             mService.mScreenRect.set(0, 0, dw, dh);
         }
 
-        mService.mPolicy.getContentRectLw(mService.mTmpContentRect);
-        displayContent.resize(mService.mTmpContentRect);
+        mService.mPolicy.getContentRectLw(mTmpContentRect);
+        displayContent.resize(mTmpContentRect);
 
         int seq = mService.mLayoutSeq+1;
         if (seq < 0) seq = 0;
@@ -1192,7 +1193,7 @@
                     // if app window is removed, or window relayout to invisible. We don't want to
                     // clear it out for windows that get replaced, because the animation depends on
                     // the flag to remove the replaced window.
-                    if (win.mAppToken == null || !win.mAppToken.mWillReplaceWindow) {
+                    if (!win.mWillReplaceWindow) {
                         win.mExiting = false;
                     }
                     if (win.mWinAnimator.mAnimLayer > layer) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9c9a5da..4c8474a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -206,6 +206,7 @@
     void reloadCalibration();
     void setPointerIconShape(int32_t iconId);
     void reloadPointerIcons();
+    void setCustomPointerIcon(const SpriteIcon& icon);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
@@ -248,6 +249,7 @@
     virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
             std::map<int32_t, PointerAnimation>* outAnimationResources);
     virtual int32_t getDefaultPointerIconId();
+    virtual int32_t getCustomPointerIconId();
 
 private:
     sp<InputManager> mInputManager;
@@ -790,6 +792,14 @@
     }
 }
 
+void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) {
+    AutoMutex _l(mLock);
+    sp<PointerController> controller = mLocked.pointerController.promote();
+    if (controller != NULL) {
+        controller->setCustomPointerIcon(icon);
+    }
+}
+
 TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
         JNIEnv *env, jfloatArray matrixArr) {
     ScopedFloatArrayRO matrix(env, matrixArr);
@@ -1090,6 +1100,10 @@
     return POINTER_ICON_STYLE_ARROW;
 }
 
+int32_t NativeInputManager::getCustomPointerIconId() {
+    return POINTER_ICON_STYLE_CUSTOM;
+}
+
 // ----------------------------------------------------------------------------
 
 static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
@@ -1437,6 +1451,20 @@
     im->reloadPointerIcons();
 }
 
+static void nativeSetCustomPointerIcon(JNIEnv* env, jclass /* clazz */,
+                                       jlong ptr, jobject iconObj) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    PointerIcon pointerIcon;
+    android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+
+    SpriteIcon spriteIcon;
+    pointerIcon.bitmap.copyTo(&spriteIcon.bitmap, kN32_SkColorType);
+    spriteIcon.hotSpotX = pointerIcon.hotSpotX;
+    spriteIcon.hotSpotY = pointerIcon.hotSpotY;
+    im->setCustomPointerIcon(spriteIcon);
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -1499,6 +1527,8 @@
             (void*) nativeSetPointerIconShape },
     { "nativeReloadPointerIcons", "(J)V",
             (void*) nativeReloadPointerIcons },
+    { "nativeSetCustomPointerIcon", "(JLandroid/view/PointerIcon;)V",
+            (void*) nativeSetCustomPointerIcon },
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5cf8ac0..c540e05 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -109,8 +109,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.PrintWriterPrinter;
-import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -1752,11 +1750,7 @@
 
         try {
             return new DeviceAdminInfo(mContext, ri);
-        } catch (XmlPullParserException e) {
-            Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
-                    e);
-            return null;
-        } catch (IOException e) {
+        } catch (XmlPullParserException | IOException e) {
             Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
                     e);
             return null;
@@ -1994,18 +1988,11 @@
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
-        } catch (NullPointerException e) {
-            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
-        } catch (NumberFormatException e) {
-            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
-        } catch (XmlPullParserException e) {
-            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (FileNotFoundException e) {
             // Don't be noisy, this is normal if we haven't defined any policies.
-        } catch (IOException e) {
-            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
-        } catch (IndexOutOfBoundsException e) {
-            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
+        } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException
+                | IndexOutOfBoundsException e) {
+            Slog.w(LOG_TAG, "failed parsing " + file, e);
         }
         try {
             if (stream != null) {
@@ -5807,7 +5794,7 @@
                     throw new SecurityException("Device owner cannot set user restriction " + key);
                 }
             } else { // profile owner
-                if (!UserRestrictionsUtils.canProfileOwnerChange(key)) {
+                if (!UserRestrictionsUtils.canProfileOwnerChange(key, userHandle)) {
                     throw new SecurityException("Profile owner cannot set user restriction " + key);
                 }
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2f33d7c..189ed33 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -150,6 +150,7 @@
     // TODO: remove all of these references by improving dependency resolution and boot phases
     private PowerManagerService mPowerManagerService;
     private ActivityManagerService mActivityManagerService;
+    private WebViewUpdateService mWebViewUpdateService;
     private DisplayManagerService mDisplayManagerService;
     private PackageManagerService mPackageManagerService;
     private PackageManager mPackageManager;
@@ -409,7 +410,7 @@
                 LocalServices.getService(UsageStatsManagerInternal.class));
 
         // Tracks whether the updatable WebView is in a ready state and watches for update installs.
-        mSystemServiceManager.startService(WebViewUpdateService.class);
+        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
     }
 
     /**
@@ -1180,7 +1181,7 @@
 
                 Slog.i(TAG, "WebViewFactory preparation");
                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
-                WebViewFactory.prepareWebViewInSystemServer();
+                mWebViewUpdateService.prepareWebViewInSystemServer();
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 812d9b6..2329b42 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -389,7 +389,6 @@
     }
 
     private void scheduleRenew() {
-        mRenewAlarm.cancel();
         if (mDhcpLeaseExpiry != 0) {
             long now = SystemClock.elapsedRealtime();
             long alarmTime = (now + mDhcpLeaseExpiry) / 2;
@@ -822,6 +821,11 @@
                     return NOT_HANDLED;
             }
         }
+
+        @Override
+        public void exit() {
+            mRenewAlarm.cancel();
+        }
     }
 
     class DhcpRenewingState extends PacketRetransmittingState {
diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
index 757f1c6..13657ab 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
@@ -21,6 +21,7 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserHandle;
 
@@ -165,6 +166,11 @@
     }
 
     @Override
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+        sendBroadcast(intent);
+    }
+
+    @Override
     public void removeStickyBroadcast(Intent intent) {
         // ignored
     }
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index d0065cd..df7b412 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -64,8 +64,8 @@
                 .setWhen(1205)
                 .setTopic(new Notification.Topic("A", "a"))
                 .build();
-        mRecordGroupGSortA = new NotificationRecord(new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user), 0);
+        mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
+                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user));
 
         mNotiGroupGSortB = new Notification.Builder(getContext())
                 .setContentTitle("B")
@@ -74,24 +74,24 @@
                 .setWhen(1200)
                 .setTopic(new Notification.Topic("A", "a"))
                 .build();
-        mRecordGroupGSortB = new NotificationRecord(new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user), 0);
+        mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
+                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user));
 
         mNotiNoGroup = new Notification.Builder(getContext())
                 .setContentTitle("C")
                 .setWhen(1201)
                 .setTopic(new Notification.Topic("C", "c"))
                 .build();
-        mRecordNoGroup = new NotificationRecord(new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user), 0);
+        mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
+                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user));
 
         mNotiNoGroup2 = new Notification.Builder(getContext())
                 .setContentTitle("D")
                 .setWhen(1202)
                 .setTopic(new Notification.Topic("D", "d"))
                 .build();
-        mRecordNoGroup2 = new NotificationRecord(new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user), 0);
+        mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
+                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user));
 
         mNotiNoGroupSortA = new Notification.Builder(getContext())
                 .setContentTitle("E")
@@ -99,8 +99,8 @@
                 .setSortKey("A")
                 .setTopic(new Notification.Topic("E", "e"))
                 .build();
-        mRecordNoGroupSortA = new NotificationRecord(new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user), 0);
+        mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
+                "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user));
     }
 
     @SmallTest
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 5542a4f..5bdf6f7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.os.UserHandle;
 import com.android.server.devicepolicy.DpmTestUtils;
 
 import android.os.Bundle;
@@ -87,10 +88,25 @@
     }
 
     public void testCanProfileOwnerChange() {
-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(UserManager.DISALLOW_RECORD_AUDIO));
-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(UserManager.DISALLOW_WALLPAPER));
-        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(UserManager.DISALLOW_ADD_USER));
-        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(UserManager.DISALLOW_ADJUST_VOLUME));
+        int user = UserHandle.USER_SYSTEM;
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_RECORD_AUDIO, user));
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_WALLPAPER, user));
+        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_ADD_USER, user));
+        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_ADJUST_VOLUME, user));
+
+        user = 10;
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_RECORD_AUDIO, user));
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_WALLPAPER, user));
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_ADD_USER, user));
+        assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_ADJUST_VOLUME, user));
     }
 
     public void testSortToGlobalAndLocal() {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 109d214..3efd0fb 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -266,8 +266,6 @@
         pw.print("  Session service="); pw.println(mInfo.getSessionService());
         pw.println("  Service info:");
         mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), "    ");
-        pw.println("  Application info:");
-        mInfo.getServiceInfo().applicationInfo.dump(new PrintWriterPrinter(pw), "    ");
         pw.print("  Recognition service="); pw.println(mInfo.getRecognitionService());
         pw.print("  Settings activity="); pw.println(mInfo.getSettingsActivity());
         pw.print("  Supports assist="); pw.println(mInfo.getSupportsAssist());
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 5ecd2b5..b18af33 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -156,6 +156,20 @@
     public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
 
     /**
+     * Flag indicating that for this {@code PhoneAccount}, the ability to make a video call to a
+     * number relies on presence.  Should only be set if the {@code PhoneAccount} also has
+     * {@link #CAPABILITY_VIDEO_CALLING}.
+     * <p>
+     * When set, the {@link ConnectionService} is responsible for toggling the
+     * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit on the
+     * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} column to indicate whether
+     * a contact's phone number supports video calling.
+     * <p>
+     * See {@link #getCapabilities}
+     */
+    public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
+
+    /**
      * URI scheme for telephone number URIs.
      */
     public static final String SCHEME_TEL = "tel";
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 12b36b2..6ffc026 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -385,6 +385,11 @@
     public static final String KEY_VVM_TYPE_STRING = "vvm_type_string";
 
     /**
+     * Whether cellular data is required to access visual voicemail.
+     */
+    public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
+
+    /**
      * The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
      * and carrier visual voicemail are not active at the same time.
      */
@@ -599,6 +604,7 @@
         sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
         sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
         sDefaults.putString(KEY_VVM_TYPE_STRING, "");
+        sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN,false);
         sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
         sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 4c3b598..64d2978 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -433,6 +433,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
             UserHandle user, BroadcastReceiver resultReceiver,
@@ -695,22 +701,26 @@
     }
 
     @Override
-    public Context createDeviceEncryptedContext(Context context) {
+    public Context createDeviceEncryptedStorageContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @SystemApi
+    @Override
+    public Context createCredentialEncryptedStorageContext() {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public Context createCredentialEncryptedContext(Context context) {
+    public boolean isDeviceEncryptedStorage() {
         throw new UnsupportedOperationException();
     }
 
+    /** {@hide} */
+    @SystemApi
     @Override
-    public boolean isDeviceEncrypted() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isCredentialEncrypted() {
+    public boolean isCredentialEncryptedStorage() {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
index 69b2a9d..0c36063 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
@@ -44,4 +44,12 @@
         }
         return anchor.getTrustedCert();
     }
+
+    public X509Certificate findByIssuerAndSignature(X509Certificate cert) {
+        java.security.cert.TrustAnchor anchor = mIndex.findByIssuerAndSignature(cert);
+        if (anchor == null) {
+            return null;
+        }
+        return anchor.getTrustedCert();
+    }
 }
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 998bb68..35e3ef4 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -22,6 +22,7 @@
 import android.util.ArraySet;
 import android.util.Pair;
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.Socket;
 import java.net.URL;
 import java.security.KeyStore;
@@ -34,6 +35,7 @@
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 
@@ -103,6 +105,15 @@
         TestUtils.assertConnectionFails(context, "developer.android.com", 443);
         TestUtils.assertUrlConnectionFails(context, "google.com", 443);
         TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
+        // Check that sockets created without the hostname fail with per-domain configs
+        SSLSocket socket = (SSLSocket) context.getSocketFactory()
+                .createSocket(InetAddress.getByName("android.com"), 443);
+        try {
+        socket.startHandshake();
+        socket.getInputStream();
+        fail();
+        } catch (IOException expected) {
+        }
     }
 
     public void testBasicPinning() throws Exception {
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 8eb30d2..cf1a4aa 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -162,8 +162,11 @@
 
         new Test("with topic Hello") {
             public void run() {
+                Notification.BigTextStyle bigText = new Notification.BigTextStyle();
+                bigText.bigText("FgBHreherhethethethe\ntwetwrterter\netetweterteryetry");
                 Notification n = new Notification.Builder(NotificationTestList.this)
                         .setSmallIcon(R.drawable.icon1)
+                        .setStyle(bigText)
                         .setWhen(mActivityCreateTime)
                         .setContentTitle("hihi")
                         .setContentText("This is a notification!!!")
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 21f47bc2..0bb88a7 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -383,6 +383,16 @@
     }
 }
 
+static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
+    printf("uses-permission-sdk-23: ");
+
+    printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
+    if (maxSdkVersion != -1) {
+        printf(" maxSdkVersion='%d'", maxSdkVersion);
+    }
+    printf("\n");
+}
+
 static void printUsesImpliedPermission(const String8& name, const String8& reason) {
     printf("uses-implied-permission: name='%s' reason='%s'\n",
             ResTable::normalizeForOutput(name.string()).string(),
@@ -463,12 +473,20 @@
  * a pre-requisite or some other reason.
  */
 struct ImpliedFeature {
+    ImpliedFeature() : impliedBySdk23(false) {}
+    ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
+
     /**
      * Name of the implied feature.
      */
     String8 name;
 
     /**
+     * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
+     */
+    bool impliedBySdk23;
+
+    /**
      * List of human-readable reasons for why this feature was implied.
      */
     SortedVector<String8> reasons;
@@ -497,18 +515,24 @@
 };
 
 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
-        const char* name, const char* reason) {
+                              const char* name, const char* reason, bool sdk23) {
     String8 name8(name);
     ssize_t idx = impliedFeatures->indexOfKey(name8);
     if (idx < 0) {
-        idx = impliedFeatures->add(name8, ImpliedFeature());
-        impliedFeatures->editValueAt(idx).name = name8;
+        idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
     }
-    impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
+
+    ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
+
+    // A non-sdk 23 implied feature takes precedence.
+    if (feature->impliedBySdk23 && !sdk23) {
+        feature->impliedBySdk23 = false;
+    }
+    feature->reasons.add(String8(reason));
 }
 
-static void printFeatureGroup(const FeatureGroup& grp,
-        const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
+static void printFeatureGroupImpl(const FeatureGroup& grp,
+                                  const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
     printf("feature-group: label='%s'\n", grp.label.string());
 
     if (grp.openGLESVersion > 0) {
@@ -536,9 +560,11 @@
 
         String8 printableFeatureName(ResTable::normalizeForOutput(
                     impliedFeature.name.string()));
-        printf("  uses-feature: name='%s'\n", printableFeatureName.string());
-        printf("  uses-implied-feature: name='%s' reason='",
-                printableFeatureName.string());
+        const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
+
+        printf("  uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
+        printf("  uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
+               printableFeatureName.string());
         const size_t numReasons = impliedFeature.reasons.size();
         for (size_t j = 0; j < numReasons; j++) {
             printf("%s", impliedFeature.reasons[j].string());
@@ -552,6 +578,15 @@
     }
 }
 
+static void printFeatureGroup(const FeatureGroup& grp) {
+    printFeatureGroupImpl(grp, NULL);
+}
+
+static void printDefaultFeatureGroup(const FeatureGroup& grp,
+                                     const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
+    printFeatureGroupImpl(grp, &impliedFeatures);
+}
+
 static void addParentFeatures(FeatureGroup* grp, const String8& name) {
     if (name == "android.hardware.camera.autofocus" ||
             name == "android.hardware.camera.flash") {
@@ -572,6 +607,72 @@
     }
 }
 
+static void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
+                                            KeyedVector<String8, ImpliedFeature>* impliedFeatures,
+                                            bool impliedBySdk23Permission) {
+    if (name == "android.permission.CAMERA") {
+        addImpliedFeature(impliedFeatures, "android.hardware.camera",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
+        addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+        addImpliedFeature(impliedFeatures, "android.hardware.location",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
+        addImpliedFeature(impliedFeatures, "android.hardware.location",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
+        addImpliedFeature(impliedFeatures, "android.hardware.location.network",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+        addImpliedFeature(impliedFeatures, "android.hardware.location",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+               name == "android.permission.INSTALL_LOCATION_PROVIDER") {
+        addImpliedFeature(impliedFeatures, "android.hardware.location",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.BLUETOOTH" ||
+               name == "android.permission.BLUETOOTH_ADMIN") {
+        if (targetSdk > 4) {
+            addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
+                    String8::format("requested %s permission", name.string())
+                    .string(), impliedBySdk23Permission);
+            addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
+                    "targetSdkVersion > 4", impliedBySdk23Permission);
+        }
+    } else if (name == "android.permission.RECORD_AUDIO") {
+        addImpliedFeature(impliedFeatures, "android.hardware.microphone",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
+               name == "android.permission.CHANGE_WIFI_STATE" ||
+               name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
+        addImpliedFeature(impliedFeatures, "android.hardware.wifi",
+                String8::format("requested %s permission", name.string())
+                .string(), impliedBySdk23Permission);
+    } else if (name == "android.permission.CALL_PHONE" ||
+               name == "android.permission.CALL_PRIVILEGED" ||
+               name == "android.permission.MODIFY_PHONE_STATE" ||
+               name == "android.permission.PROCESS_OUTGOING_CALLS" ||
+               name == "android.permission.READ_SMS" ||
+               name == "android.permission.RECEIVE_SMS" ||
+               name == "android.permission.RECEIVE_MMS" ||
+               name == "android.permission.RECEIVE_WAP_PUSH" ||
+               name == "android.permission.SEND_SMS" ||
+               name == "android.permission.WRITE_APN_SETTINGS" ||
+               name == "android.permission.WRITE_SMS") {
+        addImpliedFeature(impliedFeatures, "android.hardware.telephony",
+                String8("requested a telephony permission").string(),
+                impliedBySdk23Permission);
+    }
+}
+
 /*
  * Handle the "dump" command, to extract select data from an archive.
  */
@@ -712,7 +813,8 @@
             size_t len;
             ResXMLTree::event_code_t code;
             int depth = 0;
-            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
+                    code != ResXMLTree::BAD_DOCUMENT) {
                 if (code == ResXMLTree::END_TAG) {
                     depth--;
                     continue;
@@ -735,25 +837,53 @@
                     }
                     String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
                     printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
-                } else if (depth == 2 && tag == "permission") {
-                    String8 error;
-                    String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
-                    if (error != "") {
-                        fprintf(stderr, "ERROR: %s\n", error.string());
-                        goto bail;
+                } else if (depth == 2) {
+                    if (tag == "permission") {
+                        String8 error;
+                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR: %s\n", error.string());
+                            goto bail;
+                        }
+
+                        if (name == "") {
+                            fprintf(stderr, "ERROR: missing 'android:name' for permission\n");
+                            goto bail;
+                        }
+                        printf("permission: %s\n",
+                                ResTable::normalizeForOutput(name.string()).string());
+                    } else if (tag == "uses-permission") {
+                        String8 error;
+                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR: %s\n", error.string());
+                            goto bail;
+                        }
+
+                        if (name == "") {
+                            fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
+                            goto bail;
+                        }
+                        printUsesPermission(name,
+                                AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
+                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+                    } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
+                        String8 error;
+                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR: %s\n", error.string());
+                            goto bail;
+                        }
+
+                        if (name == "") {
+                            fprintf(stderr, "ERROR: missing 'android:name' for "
+                                    "uses-permission-sdk-23\n");
+                            goto bail;
+                        }
+                        printUsesPermissionSdk23(
+                                name,
+                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
                     }
-                    printf("permission: %s\n",
-                            ResTable::normalizeForOutput(name.string()).string());
-                } else if (depth == 2 && tag == "uses-permission") {
-                    String8 error;
-                    String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
-                    if (error != "") {
-                        fprintf(stderr, "ERROR: %s\n", error.string());
-                        goto bail;
-                    }
-                    printUsesPermission(name,
-                            AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
-                            AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
                 }
             }
         } else if (strcmp("badging", option) == 0) {
@@ -893,7 +1023,8 @@
             Vector<FeatureGroup> featureGroups;
             KeyedVector<String8, ImpliedFeature> impliedFeatures;
 
-            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
+                    code != ResXMLTree::BAD_DOCUMENT) {
                 if (code == ResXMLTree::END_TAG) {
                     depth--;
                     if (depth < 2) {
@@ -924,8 +1055,10 @@
                                             ResTable::normalizeForOutput(aName.string()).string());
                                 }
                                 printf(" label='%s' icon='%s'\n",
-                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
-                                        ResTable::normalizeForOutput(activityIcon.string()).string());
+                                       ResTable::normalizeForOutput(activityLabel.string())
+                                                .string(),
+                                       ResTable::normalizeForOutput(activityIcon.string())
+                                                .string());
                             }
                             if (isLeanbackLauncherActivity) {
                                 printf("leanback-launchable-activity:");
@@ -934,9 +1067,12 @@
                                             ResTable::normalizeForOutput(aName.string()).string());
                                 }
                                 printf(" label='%s' icon='%s' banner='%s'\n",
-                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
-                                        ResTable::normalizeForOutput(activityIcon.string()).string(),
-                                        ResTable::normalizeForOutput(activityBanner.string()).string());
+                                       ResTable::normalizeForOutput(activityLabel.string())
+                                                .string(),
+                                       ResTable::normalizeForOutput(activityIcon.string())
+                                                .string(),
+                                       ResTable::normalizeForOutput(activityBanner.string())
+                                                .string());
                             }
                         }
                         if (!hasIntentFilter) {
@@ -964,18 +1100,21 @@
                                 hasLauncher |= catLauncher;
                                 hasCameraActivity |= actCamera;
                                 hasCameraSecureActivity |= actCameraSecure;
-                                hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
+                                hasOtherActivities |=
+                                        !actMainActivity && !actCamera && !actCameraSecure;
                             } else if (withinReceiver) {
                                 hasWidgetReceivers |= actWidgetReceivers;
                                 hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
                                         hasBindDeviceAdminPermission);
-                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
+                                hasOtherReceivers |=
+                                        (!actWidgetReceivers && !actDeviceAdminEnabled);
                             } else if (withinService) {
                                 hasImeService |= actImeService;
                                 hasWallpaperService |= actWallpaperService;
                                 hasAccessibilityService |= (actAccessibilityService &&
                                         hasBindAccessibilityServicePermission);
-                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
+                                hasPrintService |=
+                                        (actPrintService && hasBindPrintServicePermission);
                                 hasNotificationListenerService |= actNotificationListenerService &&
                                         hasBindNotificationListenerServicePermission;
                                 hasDreamService |= actDreamService && hasBindDreamServicePermission;
@@ -984,7 +1123,8 @@
                                         !actHostApduService && !actOffHostApduService &&
                                         !actNotificationListenerService);
                             } else if (withinProvider) {
-                                hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
+                                hasDocumentsProvider |=
+                                        actDocumentsProvider && hasRequiredSafAttributes;
                             }
                         }
                         withinIntentFilter = false;
@@ -1125,7 +1265,8 @@
                             goto bail;
                         }
 
-                        String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR, &error);
+                        String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
+                                                                       &error);
                         if (error != "") {
                             fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
                                     error.string());
@@ -1135,7 +1276,8 @@
                                 ResTable::normalizeForOutput(label.string()).string());
                         printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
                         if (banner != "") {
-                            printf(" banner='%s'", ResTable::normalizeForOutput(banner.string()).string());
+                            printf(" banner='%s'",
+                                   ResTable::normalizeForOutput(banner.string()).string());
                         }
                         printf("\n");
                         if (testOnly != 0) {
@@ -1178,13 +1320,15 @@
                             }
                         }
                     } else if (tag == "uses-sdk") {
-                        int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+                        int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR,
+                                                                    &error);
                         if (error != "") {
                             error = "";
                             String8 name = AaptXml::getResolvedAttribute(res, tree,
                                     MIN_SDK_VERSION_ATTR, &error);
                             if (error != "") {
-                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
+                                fprintf(stderr,
+                                        "ERROR getting 'android:minSdkVersion' attribute: %s\n",
                                         error.string());
                                 goto bail;
                             }
@@ -1205,7 +1349,8 @@
                             String8 name = AaptXml::getResolvedAttribute(res, tree,
                                     TARGET_SDK_VERSION_ATTR, &error);
                             if (error != "") {
-                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
+                                fprintf(stderr,
+                                        "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
                                         error.string());
                                 goto bail;
                             }
@@ -1297,90 +1442,58 @@
                         }
                     } else if (tag == "uses-permission") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
-                        if (name != "" && error == "") {
-                            if (name == "android.permission.CAMERA") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.camera",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
-                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.BLUETOOTH" ||
-                                       name == "android.permission.BLUETOOTH_ADMIN") {
-                                if (targetSdk > 4) {
-                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
-                                            String8::format("requested %s permission", name.string())
-                                            .string());
-                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
-                                            "targetSdkVersion > 4");
-                                }
-                            } else if (name == "android.permission.RECORD_AUDIO") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
-                                       name == "android.permission.CHANGE_WIFI_STATE" ||
-                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
-                                        String8::format("requested %s permission", name.string())
-                                        .string());
-                            } else if (name == "android.permission.CALL_PHONE" ||
-                                       name == "android.permission.CALL_PRIVILEGED" ||
-                                       name == "android.permission.MODIFY_PHONE_STATE" ||
-                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
-                                       name == "android.permission.READ_SMS" ||
-                                       name == "android.permission.RECEIVE_SMS" ||
-                                       name == "android.permission.RECEIVE_MMS" ||
-                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
-                                       name == "android.permission.SEND_SMS" ||
-                                       name == "android.permission.WRITE_APN_SETTINGS" ||
-                                       name == "android.permission.WRITE_SMS") {
-                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
-                                        String8("requested a telephony permission").string());
-                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
-                                hasWriteExternalStoragePermission = true;
-                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
-                                hasReadExternalStoragePermission = true;
-                            } else if (name == "android.permission.READ_PHONE_STATE") {
-                                hasReadPhoneStatePermission = true;
-                            } else if (name == "android.permission.READ_CONTACTS") {
-                                hasReadContactsPermission = true;
-                            } else if (name == "android.permission.WRITE_CONTACTS") {
-                                hasWriteContactsPermission = true;
-                            } else if (name == "android.permission.READ_CALL_LOG") {
-                                hasReadCallLogPermission = true;
-                            } else if (name == "android.permission.WRITE_CALL_LOG") {
-                                hasWriteCallLogPermission = true;
-                            }
-
-                            printUsesPermission(name,
-                                    AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
-                                    AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
-                       } else {
+                        if (error != "") {
                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
                                     error.string());
                             goto bail;
                         }
+
+                        if (name == "") {
+                            fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
+                            goto bail;
+                        }
+
+                        addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
+
+                        if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
+                            hasWriteExternalStoragePermission = true;
+                        } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
+                            hasReadExternalStoragePermission = true;
+                        } else if (name == "android.permission.READ_PHONE_STATE") {
+                            hasReadPhoneStatePermission = true;
+                        } else if (name == "android.permission.READ_CONTACTS") {
+                            hasReadContactsPermission = true;
+                        } else if (name == "android.permission.WRITE_CONTACTS") {
+                            hasWriteContactsPermission = true;
+                        } else if (name == "android.permission.READ_CALL_LOG") {
+                            hasReadCallLogPermission = true;
+                        } else if (name == "android.permission.WRITE_CALL_LOG") {
+                            hasWriteCallLogPermission = true;
+                        }
+
+                        printUsesPermission(name,
+                                AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
+                                AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+
+                    } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
+                        String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+                                    error.string());
+                            goto bail;
+                        }
+
+                        if (name == "") {
+                            fprintf(stderr, "ERROR: missing 'android:name' for "
+                                    "uses-permission-sdk-23\n");
+                            goto bail;
+                        }
+
+                        addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, true);
+
+                        printUsesPermissionSdk23(
+                                name, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+
                     } else if (tag == "uses-package") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
@@ -1422,7 +1535,8 @@
                     } else if (tag == "package-verifier") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
-                            String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR, &error);
+                            String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR,
+                                                                      &error);
                             if (publicKey != "" && error == "") {
                                 printf("package-verifier: name='%s' publicKey='%s'\n",
                                         ResTable::normalizeForOutput(name.string()).string(),
@@ -1485,12 +1599,18 @@
                             if (error == "") {
                                 if (orien == 0 || orien == 6 || orien == 8) {
                                     // Requests landscape, sensorLandscape, or reverseLandscape.
-                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
-                                            "one or more activities have specified a landscape orientation");
+                                    addImpliedFeature(&impliedFeatures,
+                                                      "android.hardware.screen.landscape",
+                                                      "one or more activities have specified a "
+                                                      "landscape orientation",
+                                                      false);
                                 } else if (orien == 1 || orien == 7 || orien == 9) {
                                     // Requests portrait, sensorPortrait, or reversePortrait.
-                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
-                                            "one or more activities have specified a portrait orientation");
+                                    addImpliedFeature(&impliedFeatures,
+                                                      "android.hardware.screen.portrait",
+                                                      "one or more activities have specified a "
+                                                      "portrait orientation",
+                                                      false);
                                 }
                             }
                         } else if (tag == "uses-library") {
@@ -1524,8 +1644,10 @@
                                     hasBindDeviceAdminPermission = true;
                                 }
                             } else {
-                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
-                                        " receiver '%s': %s\n", receiverName.string(), error.string());
+                                fprintf(stderr,
+                                        "ERROR getting 'android:permission' attribute for"
+                                        " receiver '%s': %s\n",
+                                        receiverName.string(), error.string());
                             }
                         } else if (tag == "service") {
                             withinService = true;
@@ -1542,20 +1664,24 @@
                             if (error == "") {
                                 if (permission == "android.permission.BIND_INPUT_METHOD") {
                                     hasBindInputMethodPermission = true;
-                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
+                                } else if (permission ==
+                                        "android.permission.BIND_ACCESSIBILITY_SERVICE") {
                                     hasBindAccessibilityServicePermission = true;
-                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
+                                } else if (permission ==
+                                        "android.permission.BIND_PRINT_SERVICE") {
                                     hasBindPrintServicePermission = true;
-                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
+                                } else if (permission ==
+                                        "android.permission.BIND_NFC_SERVICE") {
                                     hasBindNfcServicePermission = true;
-                                } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
+                                } else if (permission ==
+                                        "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
                                     hasBindNotificationListenerServicePermission = true;
                                 } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
                                     hasBindDreamServicePermission = true;
                                 }
                             } else {
-                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
-                                        " service '%s': %s\n", serviceName.string(), error.string());
+                                fprintf(stderr, "ERROR getting 'android:permission' attribute for "
+                                        "service '%s': %s\n", serviceName.string(), error.string());
                             }
                         } else if (tag == "provider") {
                             withinProvider = true;
@@ -1563,7 +1689,8 @@
                             bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
                                     EXPORTED_ATTR, &error);
                             if (error != "") {
-                                fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
+                                fprintf(stderr,
+                                        "ERROR getting 'android:exported' attribute for provider:"
                                         " %s\n", error.string());
                                 goto bail;
                             }
@@ -1571,16 +1698,17 @@
                             bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
                                     res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
                             if (error != "") {
-                                fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
-                                        " %s\n", error.string());
+                                fprintf(stderr,
+                                        "ERROR getting 'android:grantUriPermissions' attribute for "
+                                        "provider: %s\n", error.string());
                                 goto bail;
                             }
 
                             String8 permission = AaptXml::getResolvedAttribute(res, tree,
                                     PERMISSION_ATTR, &error);
                             if (error != "") {
-                                fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
-                                        " %s\n", error.string());
+                                fprintf(stderr, "ERROR getting 'android:permission' attribute for "
+                                        "provider: %s\n", error.string());
                                 goto bail;
                             }
 
@@ -1661,8 +1789,9 @@
                     } else if (withinService && tag == "meta-data") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
-                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+                            fprintf(stderr, "ERROR getting 'android:name' attribute for "
+                                    "meta-data tag in service '%s': %s\n", serviceName.string(),
+                                    error.string());
                             goto bail;
                         }
 
@@ -1676,8 +1805,9 @@
                             String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
                                     RESOURCE_ATTR, &error);
                             if (error != "") {
-                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
-                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+                                fprintf(stderr, "ERROR getting 'android:resource' attribute for "
+                                        "meta-data tag in service '%s': %s\n",
+                                        serviceName.string(), error.string());
                                 goto bail;
                             }
 
@@ -1731,15 +1861,19 @@
                                 actImeService = true;
                             } else if (action == "android.service.wallpaper.WallpaperService") {
                                 actWallpaperService = true;
-                            } else if (action == "android.accessibilityservice.AccessibilityService") {
+                            } else if (action ==
+                                    "android.accessibilityservice.AccessibilityService") {
                                 actAccessibilityService = true;
-                            } else if (action == "android.printservice.PrintService") {
+                            } else if (action =="android.printservice.PrintService") {
                                 actPrintService = true;
-                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
+                            } else if (action ==
+                                    "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
                                 actHostApduService = true;
-                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
+                            } else if (action ==
+                                    "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
                                 actOffHostApduService = true;
-                            } else if (action == "android.service.notification.NotificationListenerService") {
+                            } else if (action ==
+                                    "android.service.notification.NotificationListenerService") {
                                 actNotificationListenerService = true;
                             } else if (action == "android.service.dreams.DreamService") {
                                 actDreamService = true;
@@ -1814,12 +1948,12 @@
             }
 
             addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
-                    "default feature for all apps");
+                    "default feature for all apps", false);
 
             const size_t numFeatureGroups = featureGroups.size();
             if (numFeatureGroups == 0) {
                 // If no <feature-group> tags were defined, apply auto-implied features.
-                printFeatureGroup(commonFeatures, &impliedFeatures);
+                printDefaultFeatureGroup(commonFeatures, impliedFeatures);
 
             } else {
                 // <feature-group> tags are defined, so we ignore implied features and
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index d8e0aac..0f83980 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -31,6 +31,8 @@
 	flatten/Archive.cpp \
 	flatten/TableFlattener.cpp \
 	flatten/XmlFlattener.cpp \
+	io/FileSystem.cpp \
+	io/ZipArchive.cpp \
 	link/AutoVersioner.cpp \
 	link/ManifestFixer.cpp \
 	link/PrivateAttributeMover.cpp \
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h
index 6d752bb..054b9ee 100644
--- a/tools/aapt2/NameMangler.h
+++ b/tools/aapt2/NameMangler.h
@@ -60,7 +60,7 @@
         };
     }
 
-    bool shouldMangle(const std::u16string& package) {
+    bool shouldMangle(const std::u16string& package) const {
         if (package.empty() || mPolicy.targetPackageName == package) {
             return false;
         }
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 34dc1d5..9328b69 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -85,4 +85,12 @@
     return &iter->second;
 }
 
+bool operator<(const ResourceKey& a, const ResourceKey& b) {
+    return std::tie(a.name, a.config) < std::tie(b.name, b.config);
+}
+
+bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b) {
+    return std::tie(a.name, a.config) < std::tie(b.name, b.config);
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index a7afbb5..c71e249 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -165,6 +165,36 @@
     std::vector<SourcedResourceName> exportedSymbols;
 };
 
+/**
+ * Useful struct used as a key to represent a unique resource in associative containers.
+ */
+struct ResourceKey {
+    ResourceName name;
+    ConfigDescription config;
+};
+
+bool operator<(const ResourceKey& a, const ResourceKey& b);
+
+/**
+ * Useful struct used as a key to represent a unique resource in associative containers.
+ * Holds a reference to the name, so that name better live longer than this key!
+ */
+struct ResourceKeyRef {
+    ResourceNameRef name;
+    ConfigDescription config;
+
+    ResourceKeyRef() = default;
+    ResourceKeyRef(const ResourceNameRef& n, const ConfigDescription& c) : name(n), config(c) {
+    }
+
+    /**
+     * Prevent taking a reference to a temporary. This is bad.
+     */
+    ResourceKeyRef(ResourceName&& n, const ConfigDescription& c) = delete;
+};
+
+bool operator<(const ResourceKeyRef& a, const ResourceKeyRef& b);
+
 //
 // ResourceId implementation.
 //
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index c2ddb5c..d4c536f 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -173,7 +173,7 @@
     ResourceName name;
     Source source;
     ResourceId id;
-    SymbolState symbolState = SymbolState::kUndefined;
+    Maybe<SymbolState> symbolState;
     std::u16string comment;
     std::unique_ptr<Value> value;
     std::list<ParsedResource> childResources;
@@ -182,9 +182,9 @@
 // Recursively adds resources to the ResourceTable.
 static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
                                 IDiagnostics* diag, ParsedResource* res) {
-    if (res->symbolState != SymbolState::kUndefined) {
+    if (res->symbolState) {
         Symbol symbol;
-        symbol.state = res->symbolState;
+        symbol.state = res->symbolState.value();
         symbol.source = res->source;
         symbol.comment = res->comment;
         if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
@@ -325,6 +325,8 @@
             result = parseSymbol(parser, &parsedResource);
         } else if (elementName == u"public-group") {
             result = parsePublicGroup(parser, &parsedResource);
+        } else if (elementName == u"add-resource") {
+            result = parseAddResource(parser, &parsedResource);
         } else {
             // Try parsing the elementName (or type) as a resource. These shall only be
             // resources like 'layout' or 'xml' and they can only be references.
@@ -643,7 +645,7 @@
     return !error;
 }
 
-bool ResourceParser::parseSymbol(xml::XmlPullParser* parser, ParsedResource* outResource) {
+bool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) {
     const Source source = mSource.withLine(parser->getLineNumber());
 
     Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
@@ -661,10 +663,25 @@
     }
 
     outResource->name.type = *parsedType;
-    outResource->symbolState = SymbolState::kPrivate;
     return true;
 }
 
+bool ResourceParser::parseSymbol(xml::XmlPullParser* parser, ParsedResource* outResource) {
+    if (parseSymbolImpl(parser, outResource)) {
+        outResource->symbolState = SymbolState::kPrivate;
+        return true;
+    }
+    return false;
+}
+
+bool ResourceParser::parseAddResource(xml::XmlPullParser* parser, ParsedResource* outResource) {
+    if (parseSymbolImpl(parser, outResource)) {
+        outResource->symbolState = SymbolState::kUndefined;
+        return true;
+    }
+    return false;
+}
+
 static uint32_t parseFormatType(const StringPiece16& piece) {
     if (piece == u"reference")      return android::ResTable_map::TYPE_REFERENCE;
     else if (piece == u"string")    return android::ResTable_map::TYPE_STRING;
@@ -870,7 +887,7 @@
     }
 
     return Attribute::Symbol{
-            Reference(ResourceName({}, ResourceType::kId, maybeName.value().toString())),
+            Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())),
             val.data };
 }
 
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 1150758..04db577 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -83,7 +83,9 @@
     bool parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource);
+    bool parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parseSymbol(xml::XmlPullParser* parser, ParsedResource* outResource);
+    bool parseAddResource(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource, bool weak);
     Maybe<Attribute::Symbol> parseEnumOrFlagItem(xml::XmlPullParser* parser,
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 6e0812b..84f67c6 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -563,4 +563,16 @@
     ASSERT_FALSE(testParse(input));
 }
 
+TEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
+    std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF";
+    ASSERT_TRUE(testParse(input));
+
+    Maybe<ResourceTable::SearchResult> result = mTable.findResource(
+            test::parseNameOrDie(u"@string/bar"));
+    AAPT_ASSERT_TRUE(result);
+    const ResourceEntry* entry = result.value().entry;
+    ASSERT_NE(nullptr, entry);
+    EXPECT_EQ(SymbolState::kUndefined, entry->symbolStatus.state);
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 73d8585..8a3d047 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -101,7 +101,7 @@
     if (iter != last && (*iter)->type == type) {
         return iter->get();
     }
-    return types.emplace(iter, new ResourceTableType{ type })->get();
+    return types.emplace(iter, new ResourceTableType(type))->get();
 }
 
 ResourceEntry* ResourceTableType::findEntry(const StringPiece16& name) {
@@ -121,7 +121,7 @@
     if (iter != last && name == (*iter)->name) {
         return iter->get();
     }
-    return entries.emplace(iter, new ResourceEntry{ name })->get();
+    return entries.emplace(iter, new ResourceEntry(name))->get();
 }
 
 /**
@@ -342,11 +342,6 @@
                                        IDiagnostics* diag) {
     assert(diag && "diagnostics can't be nullptr");
 
-    if (symbol.state == SymbolState::kUndefined) {
-        // Nothing to do.
-        return true;
-    }
-
     auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
     if (badCharIter != name.entry.end()) {
         diag->error(DiagMessage(symbol.source)
@@ -400,23 +395,30 @@
         return false;
     }
 
-    // Only mark the type state as public, it doesn't care about being private.
-    if (symbol.state == SymbolState::kPublic) {
-        type->symbolStatus.state = SymbolState::kPublic;
-    }
-
-    // Downgrading to a private symbol from a public one is not allowed.
-    if (entry->symbolStatus.state != SymbolState::kPublic) {
-        if (entry->symbolStatus.state != symbol.state) {
-            entry->symbolStatus = std::move(symbol);
-        }
-    }
-
     if (resId.isValid()) {
         package->id = resId.packageId();
         type->id = resId.typeId();
         entry->id = resId.entryId();
     }
+
+    // Only mark the type state as public, it doesn't care about being private.
+    if (symbol.state == SymbolState::kPublic) {
+        type->symbolStatus.state = SymbolState::kPublic;
+    }
+
+    if (symbol.state == SymbolState::kUndefined &&
+            entry->symbolStatus.state != SymbolState::kUndefined) {
+        // We can't undefine a symbol (remove its visibility). Ignore.
+        return true;
+    }
+
+    if (symbol.state == SymbolState::kPrivate &&
+            entry->symbolStatus.state == SymbolState::kPublic) {
+        // We can't downgrade public to private. Ignore.
+        return true;
+    }
+
+    entry->symbolStatus = std::move(symbol);
     return true;
 }
 
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index ffe6595..36c3e70 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
+#include "NameMangler.h"
 #include "ResourceUtils.h"
 #include "flatten/ResourceTypeExtensions.h"
+#include "util/Files.h"
 #include "util/Util.h"
 
 #include <androidfw/ResourceTypes.h>
@@ -554,5 +556,22 @@
     return {};
 }
 
+std::string buildResourceFileName(const ResourceFile& resFile, const NameMangler* mangler) {
+    std::stringstream out;
+    out << "res/" << resFile.name.type;
+    if (resFile.config != ConfigDescription{}) {
+        out << "-" << resFile.config;
+    }
+    out << "/";
+
+    if (mangler && mangler->shouldMangle(resFile.name.package)) {
+        out << NameMangler::mangleEntry(resFile.name.package, resFile.name.entry);
+    } else {
+        out << resFile.name.entry;
+    }
+    out << file::getExtension(resFile.source.path);
+    return out.str();
+}
+
 } // namespace ResourceUtils
 } // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index f93a4c7..64ca971 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -17,6 +17,7 @@
 #ifndef AAPT_RESOURCEUTILS_H
 #define AAPT_RESOURCEUTILS_H
 
+#include "NameMangler.h"
 #include "Resource.h"
 #include "ResourceValues.h"
 #include "util/StringPiece.h"
@@ -154,6 +155,16 @@
 
 uint32_t androidTypeToAttributeTypeMask(uint16_t type);
 
+/**
+ * Returns a string path suitable for use within an APK. The path will look like:
+ *
+ * res/type[-config]/<name>.<ext>
+ *
+ * Then name may be mangled if a NameMangler is supplied (can be nullptr) and the package
+ * requires mangling.
+ */
+std::string buildResourceFileName(const ResourceFile& resFile, const NameMangler* mangler);
+
 } // namespace ResourceUtils
 } // namespace aapt
 
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 46ee914..a2f53e1 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -583,8 +583,8 @@
                     publicEntry->state = Public_entry::kPublic;
                     break;
 
-                default:
-                    assert(false && "should not serialize any other state");
+                case SymbolState::kUndefined:
+                    publicEntry->state = Public_entry::kUndefined;
                     break;
                 }
 
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 9fca398..b4d4971 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -52,6 +52,14 @@
     virtual const Source& getSource() const = 0;
 };
 
+class IFileCollectionIterator {
+public:
+    virtual ~IFileCollectionIterator() = default;
+
+    virtual bool hasNext() = 0;
+    virtual IFile* next() = 0;
+};
+
 /**
  * Interface for a collection of files, all of which share a common source. That source may
  * simply be the filesystem, or a ZIP archive.
@@ -60,10 +68,8 @@
 public:
     virtual ~IFileCollection() = default;
 
-    using const_iterator = std::vector<std::unique_ptr<IFile>>::const_iterator;
-
-    virtual const_iterator begin() const = 0;
-    virtual const_iterator end() const = 0;
+    virtual IFile* findFile(const StringPiece& path) = 0;
+    virtual std::unique_ptr<IFileCollectionIterator> iterator() = 0;
 };
 
 } // namespace io
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
new file mode 100644
index 0000000..76f87ae
--- /dev/null
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include "Source.h"
+#include "io/FileSystem.h"
+#include "util/Files.h"
+#include "util/Maybe.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <utils/FileMap.h>
+
+namespace aapt {
+namespace io {
+
+RegularFile::RegularFile(const Source& source) : mSource(source) {
+}
+
+std::unique_ptr<IData> RegularFile::openAsData() {
+    android::FileMap map;
+    if (Maybe<android::FileMap> map = file::mmapPath(mSource.path, nullptr)) {
+        return util::make_unique<MmappedData>(std::move(map.value()));
+    }
+    return {};
+}
+
+const Source& RegularFile::getSource() const {
+    return mSource;
+}
+
+FileCollectionIterator::FileCollectionIterator(FileCollection* collection) :
+        mCurrent(collection->mFiles.begin()), mEnd(collection->mFiles.end()) {
+}
+
+bool FileCollectionIterator::hasNext() {
+    return mCurrent != mEnd;
+}
+
+IFile* FileCollectionIterator::next() {
+    IFile* result = mCurrent->second.get();
+    ++mCurrent;
+    return result;
+}
+
+IFile* FileCollection::insertFile(const StringPiece& path) {
+    return (mFiles[path.toString()] = util::make_unique<RegularFile>(Source(path))).get();
+}
+
+IFile* FileCollection::findFile(const StringPiece& path) {
+    auto iter = mFiles.find(path.toString());
+    if (iter != mFiles.end()) {
+        return iter->second.get();
+    }
+    return nullptr;
+}
+
+std::unique_ptr<IFileCollectionIterator> FileCollection::iterator() {
+    return util::make_unique<FileCollectionIterator>(this);
+}
+
+} // namespace io
+} // namespace aapt
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index 5dbefcc..f0559c0 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -18,7 +18,8 @@
 #define AAPT_IO_FILESYSTEM_H
 
 #include "io/File.h"
-#include "util/Files.h"
+
+#include <map>
 
 namespace aapt {
 namespace io {
@@ -28,25 +29,28 @@
  */
 class RegularFile : public IFile {
 public:
-    RegularFile(const Source& source) : mSource(source) {
-    }
+    RegularFile(const Source& source);
 
-    std::unique_ptr<IData> openAsData() override {
-        android::FileMap map;
-        if (Maybe<android::FileMap> map = file::mmapPath(mSource.path, nullptr)) {
-            return util::make_unique<MmappedData>(std::move(map.value()));
-        }
-        return {};
-    }
-
-    const Source& getSource() const override {
-        return mSource;
-    }
+    std::unique_ptr<IData> openAsData() override;
+    const Source& getSource() const override;
 
 private:
     Source mSource;
 };
 
+class FileCollection;
+
+class FileCollectionIterator : public IFileCollectionIterator {
+public:
+    FileCollectionIterator(FileCollection* collection);
+
+    bool hasNext() override;
+    io::IFile* next() override;
+
+private:
+    std::map<std::string, std::unique_ptr<IFile>>::const_iterator mCurrent, mEnd;
+};
+
 /**
  * An IFileCollection representing the file system.
  */
@@ -55,21 +59,13 @@
     /**
      * Adds a file located at path. Returns the IFile representation of that file.
      */
-    IFile* insertFile(const StringPiece& path) {
-        mFiles.push_back(util::make_unique<RegularFile>(Source(path)));
-        return mFiles.back().get();
-    }
-
-    const_iterator begin() const override {
-        return mFiles.begin();
-    }
-
-    const_iterator end() const override {
-        return mFiles.end();
-    }
+    IFile* insertFile(const StringPiece& path);
+    IFile* findFile(const StringPiece& path) override;
+    std::unique_ptr<IFileCollectionIterator> iterator() override;
 
 private:
-    std::vector<std::unique_ptr<IFile>> mFiles;
+    friend class FileCollectionIterator;
+    std::map<std::string, std::unique_ptr<IFile>> mFiles;
 };
 
 } // namespace io
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
new file mode 100644
index 0000000..bf0f4aa
--- /dev/null
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#include "Source.h"
+#include "io/ZipArchive.h"
+#include "util/Util.h"
+
+#include <utils/FileMap.h>
+#include <ziparchive/zip_archive.h>
+
+namespace aapt {
+namespace io {
+
+ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const Source& source) :
+        mZipHandle(handle), mZipEntry(entry), mSource(source) {
+}
+
+std::unique_ptr<IData> ZipFile::openAsData() {
+    if (mZipEntry.method == kCompressStored) {
+        int fd = GetFileDescriptor(mZipHandle);
+
+        android::FileMap fileMap;
+        bool result = fileMap.create(nullptr, fd, mZipEntry.offset,
+                                     mZipEntry.uncompressed_length, true);
+        if (!result) {
+            return {};
+        }
+        return util::make_unique<MmappedData>(std::move(fileMap));
+
+    } else {
+        std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(
+                new uint8_t[mZipEntry.uncompressed_length]);
+        int32_t result = ExtractToMemory(mZipHandle, &mZipEntry, data.get(),
+                                         static_cast<uint32_t>(mZipEntry.uncompressed_length));
+        if (result != 0) {
+            return {};
+        }
+        return util::make_unique<MallocData>(std::move(data), mZipEntry.uncompressed_length);
+    }
+}
+
+const Source& ZipFile::getSource() const {
+    return mSource;
+}
+
+ZipFileCollectionIterator::ZipFileCollectionIterator(ZipFileCollection* collection) :
+        mCurrent(collection->mFiles.begin()), mEnd(collection->mFiles.end()) {
+}
+
+bool ZipFileCollectionIterator::hasNext() {
+    return mCurrent != mEnd;
+}
+
+IFile* ZipFileCollectionIterator::next() {
+    IFile* result = mCurrent->second.get();
+    ++mCurrent;
+    return result;
+}
+
+ZipFileCollection::ZipFileCollection() : mHandle(nullptr) {
+}
+
+std::unique_ptr<ZipFileCollection> ZipFileCollection::create(const StringPiece& path,
+                                                             std::string* outError) {
+    std::unique_ptr<ZipFileCollection> collection = std::unique_ptr<ZipFileCollection>(
+            new ZipFileCollection());
+
+    int32_t result = OpenArchive(path.data(), &collection->mHandle);
+    if (result != 0) {
+        if (outError) *outError = ErrorCodeString(result);
+        return {};
+    }
+
+    ZipString suffix(".flat");
+    void* cookie = nullptr;
+    result = StartIteration(collection->mHandle, &cookie, nullptr, &suffix);
+    if (result != 0) {
+        if (outError) *outError = ErrorCodeString(result);
+        return {};
+    }
+
+    using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>;
+    IterationEnder iterationEnder(cookie, EndIteration);
+
+    ZipString zipEntryName;
+    ZipEntry zipData;
+    while ((result = Next(cookie, &zipData, &zipEntryName)) == 0) {
+        std::string zipEntryPath = std::string(reinterpret_cast<const char*>(zipEntryName.name),
+                                               zipEntryName.name_length);
+        std::string nestedPath = path.toString() + "@" + zipEntryPath;
+        collection->mFiles[zipEntryPath] = util::make_unique<ZipFile>(collection->mHandle,
+                                                                      zipData,
+                                                                      Source(nestedPath));
+    }
+
+    if (result != -1) {
+        if (outError) *outError = ErrorCodeString(result);
+        return {};
+    }
+    return collection;
+}
+
+IFile* ZipFileCollection::findFile(const StringPiece& path) {
+    auto iter = mFiles.find(path.toString());
+    if (iter != mFiles.end()) {
+        return iter->second.get();
+    }
+    return nullptr;
+}
+
+std::unique_ptr<IFileCollectionIterator> ZipFileCollection::iterator() {
+    return util::make_unique<ZipFileCollectionIterator>(this);
+}
+
+ZipFileCollection::~ZipFileCollection() {
+    if (mHandle) {
+        CloseArchive(mHandle);
+    }
+}
+
+} // namespace io
+} // namespace aapt
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index 98afc49..5ad119d 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -20,7 +20,7 @@
 #include "io/File.h"
 #include "util/StringPiece.h"
 
-#include <utils/FileMap.h>
+#include <map>
 #include <ziparchive/zip_archive.h>
 
 namespace aapt {
@@ -32,37 +32,10 @@
  */
 class ZipFile : public IFile {
 public:
-    ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const Source& source) :
-            mZipHandle(handle), mZipEntry(entry), mSource(source) {
-    }
+    ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const Source& source);
 
-    std::unique_ptr<IData> openAsData() override {
-        if (mZipEntry.method == kCompressStored) {
-            int fd = GetFileDescriptor(mZipHandle);
-
-            android::FileMap fileMap;
-            bool result = fileMap.create(nullptr, fd, mZipEntry.offset,
-                                         mZipEntry.uncompressed_length, true);
-            if (!result) {
-                return {};
-            }
-            return util::make_unique<MmappedData>(std::move(fileMap));
-
-        } else {
-            std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(
-                    new uint8_t[mZipEntry.uncompressed_length]);
-            int32_t result = ExtractToMemory(mZipHandle, &mZipEntry, data.get(),
-                                             static_cast<uint32_t>(mZipEntry.uncompressed_length));
-            if (result != 0) {
-                return {};
-            }
-            return util::make_unique<MallocData>(std::move(data), mZipEntry.uncompressed_length);
-        }
-    }
-
-    const Source& getSource() const override {
-        return mSource;
-    }
+    std::unique_ptr<IData> openAsData() override;
+    const Source& getSource() const override;
 
 private:
     ZipArchiveHandle mZipHandle;
@@ -70,71 +43,38 @@
     Source mSource;
 };
 
+class ZipFileCollection;
+
+class ZipFileCollectionIterator : public IFileCollectionIterator {
+public:
+    ZipFileCollectionIterator(ZipFileCollection* collection);
+
+    bool hasNext() override;
+    io::IFile* next() override;
+
+private:
+    std::map<std::string, std::unique_ptr<IFile>>::const_iterator mCurrent, mEnd;
+};
+
 /**
  * An IFileCollection that represents a ZIP archive and the entries within it.
  */
 class ZipFileCollection : public IFileCollection {
 public:
     static std::unique_ptr<ZipFileCollection> create(const StringPiece& path,
-                                                     std::string* outError) {
-        std::unique_ptr<ZipFileCollection> collection = std::unique_ptr<ZipFileCollection>(
-                new ZipFileCollection());
+                                                     std::string* outError);
 
-        int32_t result = OpenArchive(path.data(), &collection->mHandle);
-        if (result != 0) {
-            if (outError) *outError = ErrorCodeString(result);
-            return {};
-        }
+    io::IFile* findFile(const StringPiece& path) override;
+    std::unique_ptr<IFileCollectionIterator> iterator() override;
 
-        ZipString suffix(".flat");
-        void* cookie = nullptr;
-        result = StartIteration(collection->mHandle, &cookie, nullptr, &suffix);
-        if (result != 0) {
-            if (outError) *outError = ErrorCodeString(result);
-            return {};
-        }
-
-        using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>;
-        IterationEnder iterationEnder(cookie, EndIteration);
-
-        ZipString zipEntryName;
-        ZipEntry zipData;
-        while ((result = Next(cookie, &zipData, &zipEntryName)) == 0) {
-            std::string nestedPath = path.toString();
-            nestedPath += "@" + std::string(reinterpret_cast<const char*>(zipEntryName.name),
-                                            zipEntryName.name_length);
-            collection->mFiles.push_back(util::make_unique<ZipFile>(collection->mHandle,
-                                                                    zipData,
-                                                                    Source(nestedPath)));
-        }
-
-        if (result != -1) {
-            if (outError) *outError = ErrorCodeString(result);
-            return {};
-        }
-        return collection;
-    }
-
-    const_iterator begin() const override {
-        return mFiles.begin();
-    }
-
-    const_iterator end() const override {
-        return mFiles.end();
-    }
-
-    ~ZipFileCollection() override {
-        if (mHandle) {
-            CloseArchive(mHandle);
-        }
-    }
+    ~ZipFileCollection() override;
 
 private:
-    ZipFileCollection() : mHandle(nullptr) {
-    }
+    friend class ZipFileCollectionIterator;
+    ZipFileCollection();
 
     ZipArchiveHandle mHandle;
-    std::vector<std::unique_ptr<IFile>> mFiles;
+    std::map<std::string, std::unique_ptr<IFile>> mFiles;
 };
 
 } // namespace io
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 33d9272..652e52f 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -57,6 +57,7 @@
     bool staticLib = false;
     bool verbose = false;
     bool outputToDirectory = false;
+    bool autoAddOverlay = false;
     Maybe<std::u16string> privateSymbols;
     Maybe<std::u16string> minSdkVersionDefault;
     Maybe<std::u16string> targetSdkVersionDefault;
@@ -104,23 +105,6 @@
         mCollections.push_back(std::move(fileCollection));
     }
 
-    std::string buildResourceFileName(const ResourceFile& resFile) {
-        std::stringstream out;
-        out << "res/" << resFile.name.type;
-        if (resFile.config != ConfigDescription{}) {
-            out << "-" << resFile.config;
-        }
-        out << "/";
-
-        if (mContext.getNameMangler()->shouldMangle(resFile.name.package)) {
-            out << NameMangler::mangleEntry(resFile.name.package, resFile.name.entry);
-        } else {
-            out << resFile.name.entry;
-        }
-        out << file::getExtension(resFile.source.path);
-        return out.str();
-    }
-
     /**
      * Creates a SymbolTable that loads symbols from the various APKs and caches the
      * results for faster lookup.
@@ -425,45 +409,28 @@
             return false;
         }
 
-        if (!mTableMerger->merge(file->getSource(), table.get(), override)) {
-            return false;
+        bool result = false;
+        if (override) {
+            result = mTableMerger->mergeOverlay(file->getSource(), table.get());
+        } else {
+            result = mTableMerger->merge(file->getSource(), table.get());
         }
-        return true;
+        return result;
     }
 
-    bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool override) {
-        // Apply the package name used for this compilation phase if none was specified.
-        if (fileDesc->name.package.empty()) {
-            fileDesc->name.package = mContext.getCompilationPackage().toString();
+    bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool overlay) {
+        if (mOptions.verbose) {
+            mContext.getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
         }
 
-        // Mangle the name if necessary.
-        ResourceNameRef resName = fileDesc->name;
-        Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(fileDesc->name);
-        if (mangledName) {
-            resName = mangledName.value();
-        }
-
-        // If we are overriding resources, we supply a custom resolver function.
-        std::function<int(Value*,Value*)> resolver;
-        if (override) {
-            resolver = [](Value* a, Value* b) -> int {
-                int result = ResourceTable::resolveValueCollision(a, b);
-                if (result == 0) {
-                    // Always accept the new value if it would normally conflict (override).
-                    result = 1;
-                }
-                return result;
-            };
+        bool result = false;
+        if (overlay) {
+            result = mTableMerger->mergeFileOverlay(*fileDesc, file);
         } else {
-            // Otherwise use the default resolution.
-            resolver = ResourceTable::resolveValueCollision;
+            result = mTableMerger->mergeFile(*fileDesc, file);
         }
 
-        // Add this file to the table.
-        if (!mFinalTable.addFileReference(resName, fileDesc->config, fileDesc->source,
-                                          util::utf8ToUtf16(buildResourceFileName(*fileDesc)),
-                                          resolver, mContext.getDiagnostics())) {
+        if (!result) {
             return false;
         }
 
@@ -489,10 +456,6 @@
                 return false;
             }
         }
-
-        // Now add this file for later processing. Once the table is assigned IDs, we can compile
-        // this file.
-        mFilesToProcess.insert(FileToProcess{ std::move(fileDesc), file });
         return true;
     }
 
@@ -509,8 +472,8 @@
         }
 
         bool error = false;
-        for (const std::unique_ptr<io::IFile>& file : *collection) {
-            if (!processFile(file.get(), override)) {
+        for (auto iter = collection->iterator(); iter->hasNext(); ) {
+            if (!processFile(iter->next(), override)) {
                 error = true;
             }
         }
@@ -588,7 +551,9 @@
             return 1;
         }
 
-        mTableMerger = util::make_unique<TableMerger>(&mContext, &mFinalTable);
+        TableMergerOptions tableMergerOptions;
+        tableMergerOptions.autoAddOverlay = mOptions.autoAddOverlay;
+        mTableMerger = util::make_unique<TableMerger>(&mContext, &mFinalTable, tableMergerOptions);
 
         if (mOptions.verbose) {
             mContext.getDiagnostics()->note(
@@ -698,31 +663,47 @@
             return 1;
         }
 
-        for (const FileToProcess& file : mFilesToProcess) {
-            const StringPiece path = file.file->getSource().path;
+        for (auto& mergeEntry : mTableMerger->getFilesToMerge()) {
+            const ResourceKeyRef& key = mergeEntry.first;
+            const FileToMerge& fileToMerge = mergeEntry.second;
 
-            if (file.fileExport->name.type != ResourceType::kRaw &&
-                    util::stringEndsWith<char>(path, ".xml.flat")) {
+            const StringPiece path = fileToMerge.file->getSource().path;
+
+            if (key.name.type != ResourceType::kRaw &&
+                    (util::stringEndsWith<char>(path, ".xml.flat") ||
+                    util::stringEndsWith<char>(path, ".xml"))) {
                 if (mOptions.verbose) {
                     mContext.getDiagnostics()->note(DiagMessage() << "linking " << path);
                 }
 
-                std::unique_ptr<io::IData> data = file.file->openAsData();
+                io::IFile* file = fileToMerge.file;
+                std::unique_ptr<io::IData> data = file->openAsData();
                 if (!data) {
-                    mContext.getDiagnostics()->error(DiagMessage(file.file->getSource())
+                    mContext.getDiagnostics()->error(DiagMessage(file->getSource())
                                                      << "failed to open file");
                     return 1;
                 }
 
-                std::unique_ptr<xml::XmlResource> xmlRes = loadBinaryXmlSkipFileExport(
-                        file.file->getSource(), data->data(), data->size(),
-                        mContext.getDiagnostics());
+                std::unique_ptr<xml::XmlResource> xmlRes;
+                if (util::stringEndsWith<char>(path, ".flat")) {
+                    xmlRes = loadBinaryXmlSkipFileExport(file->getSource(),
+                                                         data->data(), data->size(),
+                                                         mContext.getDiagnostics());
+                } else {
+                    xmlRes = xml::inflate(data->data(), data->size(), mContext.getDiagnostics(),
+                                          file->getSource());
+                }
+
                 if (!xmlRes) {
                     return 1;
                 }
 
-                // Move the file description over.
-                xmlRes->file = std::move(*file.fileExport);
+                // Create the file description header.
+                xmlRes->file = ResourceFile{
+                        key.name.toResourceName(),
+                        key.config,
+                        fileToMerge.originalSource,
+                };
 
                 XmlReferenceLinker xmlLinker;
                 if (xmlLinker.consume(&mContext, xmlRes.get())) {
@@ -736,7 +717,7 @@
                         maxSdkLevel = std::max<size_t>(xmlRes->file.config.sdkVersion, 1u);
                     }
 
-                    if (!flattenXml(xmlRes.get(), buildResourceFileName(xmlRes->file), maxSdkLevel,
+                    if (!flattenXml(xmlRes.get(), fileToMerge.dstPath, maxSdkLevel,
                                     archiveWriter.get())) {
                         error = true;
                     }
@@ -750,19 +731,23 @@
                                                                     xmlRes->file.config,
                                                                     sdkLevel)) {
                                 xmlRes->file.config.sdkVersion = sdkLevel;
+
+                                std::string genResourcePath = ResourceUtils::buildResourceFileName(
+                                        xmlRes->file, mContext.getNameMangler());
+
                                 bool added = mFinalTable.addFileReference(
                                         xmlRes->file.name,
                                         xmlRes->file.config,
                                         xmlRes->file.source,
-                                        util::utf8ToUtf16(buildResourceFileName(xmlRes->file)),
+                                        util::utf8ToUtf16(genResourcePath),
                                         mContext.getDiagnostics());
                                 if (!added) {
                                     error = true;
                                     continue;
                                 }
 
-                                if (!flattenXml(xmlRes.get(), buildResourceFileName(xmlRes->file),
-                                                sdkLevel, archiveWriter.get())) {
+                                if (!flattenXml(xmlRes.get(), genResourcePath, sdkLevel,
+                                                archiveWriter.get())) {
                                     error = true;
                                 }
                             }
@@ -777,7 +762,7 @@
                     mContext.getDiagnostics()->note(DiagMessage() << "copying " << path);
                 }
 
-                if (!copyFileToArchive(file.file, buildResourceFileName(*file.fileExport), 0,
+                if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath, 0,
                                        archiveWriter.get())) {
                     error = true;
                 }
@@ -845,15 +830,7 @@
 
         if (mOptions.verbose) {
             Debug::printTable(&mFinalTable);
-            for (; !mTableMerger->getFileMergeQueue()->empty();
-                    mTableMerger->getFileMergeQueue()->pop()) {
-                const FileToMerge& f = mTableMerger->getFileMergeQueue()->front();
-                mContext.getDiagnostics()->note(
-                        DiagMessage() << f.srcPath << " -> " << f.dstPath << " from (0x"
-                                      << std::hex << (uintptr_t) f.srcTable << std::dec);
-            }
         }
-
         return 0;
     }
 
@@ -861,24 +838,15 @@
     LinkOptions mOptions;
     LinkContext mContext;
     ResourceTable mFinalTable;
+
+    ResourceTable mLocalFileTable;
     std::unique_ptr<TableMerger> mTableMerger;
 
+    // A pointer to the FileCollection representing the filesystem (not archives).
     io::FileCollection* mFileCollection;
+
+    // A vector of IFileCollections. This is mainly here to keep ownership of the collections.
     std::vector<std::unique_ptr<io::IFileCollection>> mCollections;
-
-    struct FileToProcess {
-        std::unique_ptr<ResourceFile> fileExport;
-        io::IFile* file;
-    };
-
-    struct FileToProcessComparator {
-        bool operator()(const FileToProcess& a, const FileToProcess& b) {
-            return std::tie(a.fileExport->name, a.fileExport->config) <
-                    std::tie(b.fileExport->name, b.fileExport->config);
-        }
-    };
-
-    std::set<FileToProcess, FileToProcessComparator> mFilesToProcess;
 };
 
 int link(const std::vector<StringPiece>& args) {
@@ -915,6 +883,8 @@
                           "package name", &privateSymbolsPackage)
             .optionalFlagList("--extra-packages", "Generate the same R.java but with different "
                               "package names", &extraJavaPackages)
+            .optionalSwitch("--auto-add-overlay", "Allows the addition of new resources in "
+                            "overlays without <add-resource> tags", &options.autoAddOverlay)
             .optionalSwitch("-v", "Enables verbose logging", &options.verbose);
 
     if (!flags.parse("aapt2 link", args, &std::cerr)) {
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index a06a1bf..27a23bd 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "ResourceTable.h"
+#include "ResourceUtils.h"
 #include "ResourceValues.h"
 #include "ValueVisitor.h"
 
@@ -26,8 +27,9 @@
 
 namespace aapt {
 
-TableMerger::TableMerger(IAaptContext* context, ResourceTable* outTable) :
-        mContext(context), mMasterTable(outTable) {
+TableMerger::TableMerger(IAaptContext* context, ResourceTable* outTable,
+                         const TableMergerOptions& options) :
+        mContext(context), mMasterTable(outTable), mOptions(options) {
     // Create the desired package that all tables will be merged into.
     mMasterPackage = mMasterTable->createPackage(
             mContext->getCompilationPackage(), mContext->getPackageId());
@@ -37,7 +39,8 @@
 /**
  * This will merge packages with the same package name (or no package name).
  */
-bool TableMerger::merge(const Source& src, ResourceTable* table, bool overrideExisting) {
+bool TableMerger::mergeImpl(const Source& src, ResourceTable* table,
+                            bool overlay, bool allowNew) {
     const uint8_t desiredPackageId = mContext->getPackageId();
 
     bool error = false;
@@ -55,19 +58,26 @@
             // mangled, then looked up at resolution time.
             // Also, when linking, we convert references with no package name to use
             // the compilation package name.
-            if (!doMerge(src, table, package.get(), false, overrideExisting)) {
-                error = true;
-            }
+            error |= !doMerge(src, table, package.get(),
+                              false /* mangle */, overlay, allowNew, {});
         }
     }
     return !error;
 }
 
+bool TableMerger::merge(const Source& src, ResourceTable* table) {
+    return mergeImpl(src, table, false /* overlay */, true /* allow new */);
+}
+
+bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table) {
+    return mergeImpl(src, table, true /* overlay */, mOptions.autoAddOverlay);
+}
+
 /**
  * This will merge and mangle resources from a static library.
  */
 bool TableMerger::mergeAndMangle(const Source& src, const StringPiece16& packageName,
-                                 ResourceTable* table) {
+                                 ResourceTable* table, io::IFileCollection* collection) {
     bool error = false;
     for (auto& package : table->packages) {
         // Warn of packages with an unrelated ID.
@@ -79,16 +89,35 @@
 
         bool mangle = packageName != mContext->getCompilationPackage();
         mMergedPackages.insert(package->name);
-        if (!doMerge(src, table, package.get(), mangle, false)) {
-            error = true;
-        }
+
+        auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+                            FileReference* newFile, FileReference* oldFile) -> bool {
+            // The old file's path points inside the APK, so we can use it as is.
+            io::IFile* f = collection->findFile(util::utf16ToUtf8(*oldFile->path));
+            if (!f) {
+                mContext->getDiagnostics()->error(DiagMessage(src) << "file '" << *oldFile->path
+                                                  << "' not found");
+                return false;
+            }
+
+            mFilesToMerge[ResourceKeyRef{ name, config }] = FileToMerge{
+                    f, oldFile->getSource(), util::utf16ToUtf8(*newFile->path) };
+            return true;
+        };
+
+        error |= !doMerge(src, table, package.get(),
+                          mangle, false /* overlay */, true /* allow new */, callback);
     }
     return !error;
 }
 
-bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable,
-                          ResourceTablePackage* srcPackage, const bool manglePackage,
-                          const bool overrideExisting) {
+bool TableMerger::doMerge(const Source& src,
+                          ResourceTable* srcTable,
+                          ResourceTablePackage* srcPackage,
+                          const bool manglePackage,
+                          const bool overlay,
+                          const bool allowNewResources,
+                          FileMergeCallback callback) {
     bool error = false;
 
     for (auto& srcType : srcPackage->types) {
@@ -112,10 +141,33 @@
         for (auto& srcEntry : srcType->entries) {
             ResourceEntry* dstEntry;
             if (manglePackage) {
-                dstEntry = dstType->findOrCreateEntry(NameMangler::mangleEntry(
-                        srcPackage->name, srcEntry->name));
+                std::u16string mangledName = NameMangler::mangleEntry(srcPackage->name,
+                                                                      srcEntry->name);
+                if (allowNewResources) {
+                    dstEntry = dstType->findOrCreateEntry(mangledName);
+                } else {
+                    dstEntry = dstType->findEntry(mangledName);
+                }
             } else {
-                dstEntry = dstType->findOrCreateEntry(srcEntry->name);
+                if (allowNewResources) {
+                    dstEntry = dstType->findOrCreateEntry(srcEntry->name);
+                } else {
+                    dstEntry = dstType->findEntry(srcEntry->name);
+                }
+            }
+
+            if (!dstEntry) {
+                mContext->getDiagnostics()->error(DiagMessage(src)
+                                                  << "resource "
+                                                  << ResourceNameRef(srcPackage->name,
+                                                                     srcType->type,
+                                                                     srcEntry->name)
+                                                  << " does not override an existing resource");
+                mContext->getDiagnostics()->note(DiagMessage(src)
+                                                 << "define an <add-resource> tag or use "
+                                                    "--auto-add-overlay");
+                error = true;
+                continue;
             }
 
             if (srcEntry->symbolStatus.state != SymbolState::kUndefined) {
@@ -143,6 +195,8 @@
                 }
             }
 
+            ResourceNameRef resName(mMasterPackage->name, dstType->type, dstEntry->name);
+
             for (ResourceConfigValue& srcValue : srcEntry->values) {
                 auto iter = std::lower_bound(dstEntry->values.begin(), dstEntry->values.end(),
                                              srcValue.config, cmp::lessThanConfig);
@@ -150,7 +204,7 @@
                 if (iter != dstEntry->values.end() && iter->config == srcValue.config) {
                     const int collisionResult = ResourceTable::resolveValueCollision(
                             iter->value.get(), srcValue.value.get());
-                    if (collisionResult == 0 && !overrideExisting) {
+                    if (collisionResult == 0 && !overlay) {
                         // Error!
                         ResourceNameRef resourceName(srcPackage->name,
                                                      srcType->type,
@@ -175,10 +229,26 @@
                     iter = dstEntry->values.insert(iter, ResourceConfigValue{ srcValue.config });
                 }
 
-                if (manglePackage) {
-                    iter->value = cloneAndMangle(srcTable, srcPackage->name, srcValue.value.get());
+                if (FileReference* f = valueCast<FileReference>(srcValue.value.get())) {
+                    std::unique_ptr<FileReference> newFileRef;
+                    if (manglePackage) {
+                        newFileRef = cloneAndMangleFile(srcPackage->name, *f);
+                    } else {
+                        newFileRef = std::unique_ptr<FileReference>(f->clone(
+                                &mMasterTable->stringPool));
+                    }
+
+                    if (callback) {
+                        if (!callback(resName, iter->config, newFileRef.get(), f)) {
+                            error = true;
+                            continue;
+                        }
+                    }
+                    iter->value = std::move(newFileRef);
+
                 } else {
-                    iter->value = clone(srcValue.value.get());
+                    iter->value = std::unique_ptr<Value>(srcValue.value->clone(
+                            &mMasterTable->stringPool));
                 }
             }
         }
@@ -186,28 +256,52 @@
     return !error;
 }
 
-std::unique_ptr<Value> TableMerger::cloneAndMangle(ResourceTable* table,
-                                                   const std::u16string& package,
-                                                   Value* value) {
-    if (FileReference* f = valueCast<FileReference>(value)) {
-        // Mangle the path.
-        StringPiece16 prefix, entry, suffix;
-        if (util::extractResFilePathParts(*f->path, &prefix, &entry, &suffix)) {
-            std::u16string mangledEntry = NameMangler::mangleEntry(package, entry.toString());
-            std::u16string newPath = prefix.toString() + mangledEntry + suffix.toString();
-            mFilesToMerge.push(FileToMerge{ table, *f->path, newPath });
-            std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
-                    mMasterTable->stringPool.makeRef(newPath));
-            fileRef->setComment(f->getComment());
-            fileRef->setSource(f->getSource());
-            return std::move(fileRef);
-        }
+std::unique_ptr<FileReference> TableMerger::cloneAndMangleFile(const std::u16string& package,
+                                                               const FileReference& fileRef) {
+
+    StringPiece16 prefix, entry, suffix;
+    if (util::extractResFilePathParts(*fileRef.path, &prefix, &entry, &suffix)) {
+        std::u16string mangledEntry = NameMangler::mangleEntry(package, entry.toString());
+        std::u16string newPath = prefix.toString() + mangledEntry + suffix.toString();
+        std::unique_ptr<FileReference> newFileRef = util::make_unique<FileReference>(
+                mMasterTable->stringPool.makeRef(newPath));
+        newFileRef->setComment(fileRef.getComment());
+        newFileRef->setSource(fileRef.getSource());
+        return newFileRef;
     }
-    return clone(value);
+    return std::unique_ptr<FileReference>(fileRef.clone(&mMasterTable->stringPool));
 }
 
-std::unique_ptr<Value> TableMerger::clone(Value* value) {
-    return std::unique_ptr<Value>(value->clone(&mMasterTable->stringPool));
+bool TableMerger::mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay) {
+    ResourceTable table;
+    std::u16string path = util::utf8ToUtf16(ResourceUtils::buildResourceFileName(fileDesc,
+                                                                                 nullptr));
+    std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
+            table.stringPool.makeRef(path));
+    fileRef->setSource(fileDesc.source);
+
+    ResourceTablePackage* pkg = table.createPackage(fileDesc.name.package, 0x0);
+    pkg->findOrCreateType(fileDesc.name.type)
+            ->findOrCreateEntry(fileDesc.name.entry)
+            ->values.push_back(ResourceConfigValue{ fileDesc.config, std::move(fileRef) });
+
+    auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+                       FileReference* newFile, FileReference* oldFile) -> bool {
+        mFilesToMerge[ResourceKeyRef{ name, config }] = FileToMerge{
+                file, oldFile->getSource(), util::utf16ToUtf8(*newFile->path) };
+        return true;
+    };
+
+    return doMerge(file->getSource(), &table, pkg,
+                   false /* mangle */, overlay /* overlay */, true /* allow new */, callback);
+}
+
+bool TableMerger::mergeFile(const ResourceFile& fileDesc, io::IFile* file) {
+    return mergeFileImpl(fileDesc, file, false /* overlay */);
+}
+
+bool TableMerger::mergeFileOverlay(const ResourceFile& fileDesc, io::IFile* file) {
+    return mergeFileImpl(fileDesc, file, true /* overlay */);
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index a2c9dbf..e1be5d5 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -17,21 +17,40 @@
 #ifndef AAPT_TABLEMERGER_H
 #define AAPT_TABLEMERGER_H
 
+#include "Resource.h"
 #include "ResourceTable.h"
 #include "ResourceValues.h"
+#include "io/File.h"
+#include "process/IResourceTableConsumer.h"
 #include "util/Util.h"
 
-#include "process/IResourceTableConsumer.h"
-
-#include <queue>
-#include <set>
+#include <functional>
+#include <map>
 
 namespace aapt {
 
 struct FileToMerge {
-    ResourceTable* srcTable;
-    std::u16string srcPath;
-    std::u16string dstPath;
+    /**
+     * The compiled file from which to read the data.
+     */
+    io::IFile* file;
+
+    /**
+     * Where the original, uncompiled file came from.
+     */
+    Source originalSource;
+
+    /**
+     * The destination path within the APK/archive.
+     */
+    std::string dstPath;
+};
+
+struct TableMergerOptions {
+    /**
+     * If true, resources in overlays can be added without previously having existed.
+     */
+    bool autoAddOverlay = false;
 };
 
 /**
@@ -50,40 +69,74 @@
  */
 class TableMerger {
 public:
-    TableMerger(IAaptContext* context, ResourceTable* outTable);
+    /**
+     * Note: The outTable ResourceTable must live longer than this TableMerger. References
+     * are made to this ResourceTable for efficiency reasons.
+     */
+    TableMerger(IAaptContext* context, ResourceTable* outTable, const TableMergerOptions& options);
 
-    inline std::queue<FileToMerge>* getFileMergeQueue() {
-        return &mFilesToMerge;
+    const std::map<ResourceKeyRef, FileToMerge>& getFilesToMerge() {
+        return mFilesToMerge;
     }
 
-    inline const std::set<std::u16string>& getMergedPackages() const {
+    const std::set<std::u16string>& getMergedPackages() const {
         return mMergedPackages;
     }
 
     /**
      * Merges resources from the same or empty package. This is for local sources.
      */
-    bool merge(const Source& src, ResourceTable* table, bool overrideExisting);
+    bool merge(const Source& src, ResourceTable* table);
+
+    /**
+     * Merges resources from an overlay ResourceTable.
+     */
+    bool mergeOverlay(const Source& src, ResourceTable* table);
 
     /**
      * Merges resources from the given package, mangling the name. This is for static libraries.
+     * An io::IFileCollection is needed in order to find the referenced Files and process them.
      */
-    bool mergeAndMangle(const Source& src, const StringPiece16& package, ResourceTable* table);
+    bool mergeAndMangle(const Source& src, const StringPiece16& package, ResourceTable* table,
+                        io::IFileCollection* collection);
+
+    /**
+     * Merges a compiled file that belongs to this same or empty package. This is for local sources.
+     */
+    bool mergeFile(const ResourceFile& fileDesc, io::IFile* file);
+
+    /**
+     * Merges a compiled file from an overlay, overriding an existing definition.
+     */
+    bool mergeFileOverlay(const ResourceFile& fileDesc, io::IFile* file);
 
 private:
+    using FileMergeCallback = std::function<bool(const ResourceNameRef&,
+                                                 const ConfigDescription& config,
+                                                 FileReference*,
+                                                 FileReference*)>;
+
     IAaptContext* mContext;
     ResourceTable* mMasterTable;
+    TableMergerOptions mOptions;
     ResourceTablePackage* mMasterPackage;
 
     std::set<std::u16string> mMergedPackages;
-    std::queue<FileToMerge> mFilesToMerge;
+    std::map<ResourceKeyRef, FileToMerge> mFilesToMerge;
+
+    bool mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay);
+
+    bool mergeImpl(const Source& src, ResourceTable* srcTable,
+                   bool overlay, bool allowNew);
 
     bool doMerge(const Source& src, ResourceTable* srcTable, ResourceTablePackage* srcPackage,
-                 const bool manglePackage, const bool overrideExisting);
+                 const bool manglePackage,
+                 const bool overlay,
+                 const bool allowNewResources,
+                 FileMergeCallback callback);
 
-    std::unique_ptr<Value> cloneAndMangle(ResourceTable* table, const std::u16string& package,
-                                          Value* value);
-    std::unique_ptr<Value> clone(Value* value);
+    std::unique_ptr<FileReference> cloneAndMangleFile(const std::u16string& package,
+                                                      const FileReference& value);
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index b7ffba7..fa4afd3 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
+#include "io/FileSystem.h"
 #include "link/TableMerger.h"
-
 #include "test/Builders.h"
 #include "test/Context.h"
 
@@ -57,10 +57,11 @@
             .build();
 
     ResourceTable finalTable;
-    TableMerger merger(mContext.get(), &finalTable);
+    TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
+    io::FileCollection collection;
 
-    ASSERT_TRUE(merger.merge({}, tableA.get(), false));
-    ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get()));
+    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
 
     EXPECT_TRUE(merger.getMergedPackages().count(u"com.app.b") != 0);
 
@@ -76,6 +77,60 @@
     AAPT_EXPECT_TRUE(finalTable.findResource(test::parseNameOrDie(u"@com.app.a:id/com.app.b$foo")));
 }
 
+TEST_F(TableMergerTest, MergeFile) {
+    ResourceTable finalTable;
+    TableMergerOptions options;
+    options.autoAddOverlay = false;
+    TableMerger merger(mContext.get(), &finalTable, options);
+
+    ResourceFile fileDesc;
+    fileDesc.config = test::parseConfigOrDie("hdpi-v4");
+    fileDesc.name = test::parseNameOrDie(u"@layout/main");
+    fileDesc.source = Source("res/layout-hdpi/main.xml");
+    test::TestFile testFile("path/to/res/layout-hdpi/main.xml.flat");
+
+    ASSERT_TRUE(merger.mergeFile(fileDesc, &testFile));
+
+    FileReference* file = test::getValueForConfig<FileReference>(&finalTable,
+                                                                 u"@com.app.a:layout/main",
+                                                                 test::parseConfigOrDie("hdpi-v4"));
+    ASSERT_NE(nullptr, file);
+    EXPECT_EQ(std::u16string(u"res/layout-hdpi-v4/main.xml"), *file->path);
+
+    ResourceName name = test::parseNameOrDie(u"@com.app.a:layout/main");
+    ResourceKeyRef key = { name, test::parseConfigOrDie("hdpi-v4") };
+
+    auto iter = merger.getFilesToMerge().find(key);
+    ASSERT_NE(merger.getFilesToMerge().end(), iter);
+
+    const FileToMerge& actualFileToMerge = iter->second;
+    EXPECT_EQ(&testFile, actualFileToMerge.file);
+    EXPECT_EQ(std::string("res/layout-hdpi-v4/main.xml"), actualFileToMerge.dstPath);
+}
+
+TEST_F(TableMergerTest, MergeFileOverlay) {
+    ResourceTable finalTable;
+    TableMergerOptions tableMergerOptions;
+    tableMergerOptions.autoAddOverlay = false;
+    TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
+
+    ResourceFile fileDesc;
+    fileDesc.name = test::parseNameOrDie(u"@xml/foo");
+    test::TestFile fileA("path/to/fileA.xml.flat");
+    test::TestFile fileB("path/to/fileB.xml.flat");
+
+    ASSERT_TRUE(merger.mergeFile(fileDesc, &fileA));
+    ASSERT_TRUE(merger.mergeFileOverlay(fileDesc, &fileB));
+
+    ResourceName name = test::parseNameOrDie(u"@com.app.a:xml/foo");
+    ResourceKeyRef key = { name, ConfigDescription{} };
+    auto iter = merger.getFilesToMerge().find(key);
+    ASSERT_NE(merger.getFilesToMerge().end(), iter);
+
+    const FileToMerge& actualFileToMerge = iter->second;
+    EXPECT_EQ(&fileB, actualFileToMerge.file);
+}
+
 TEST_F(TableMergerTest, MergeFileReferences) {
     std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
             .setPackageId(u"com.app.a", 0x7f)
@@ -87,10 +142,12 @@
             .build();
 
     ResourceTable finalTable;
-    TableMerger merger(mContext.get(), &finalTable);
+    TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
+    io::FileCollection collection;
+    collection.insertFile("res/xml/file.xml");
 
-    ASSERT_TRUE(merger.merge({}, tableA.get(), false));
-    ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get()));
+    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get(), &collection));
 
     FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file");
     ASSERT_NE(f, nullptr);
@@ -100,13 +157,90 @@
     ASSERT_NE(f, nullptr);
     EXPECT_EQ(std::u16string(u"res/xml/com.app.b$file.xml"), *f->path);
 
-    std::queue<FileToMerge>* filesToMerge = merger.getFileMergeQueue();
-    ASSERT_FALSE(filesToMerge->empty());
+    ResourceName name = test::parseNameOrDie(u"@com.app.a:xml/com.app.b$file");
+    ResourceKeyRef key = { name, ConfigDescription{} };
+    auto iter = merger.getFilesToMerge().find(key);
+    ASSERT_NE(merger.getFilesToMerge().end(), iter);
 
-    FileToMerge& fileToMerge = filesToMerge->front();
-    EXPECT_EQ(fileToMerge.srcTable, tableB.get());
-    EXPECT_EQ(fileToMerge.srcPath, u"res/xml/file.xml");
-    EXPECT_EQ(fileToMerge.dstPath, u"res/xml/com.app.b$file.xml");
+    const FileToMerge& actualFileToMerge = iter->second;
+    EXPECT_EQ(Source("res/xml/file.xml"), actualFileToMerge.file->getSource());
+    EXPECT_EQ(std::string("res/xml/com.app.b$file.xml"), actualFileToMerge.dstPath);
+}
+
+TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
+    std::unique_ptr<ResourceTable> base = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x00)
+            .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+            .build();
+    std::unique_ptr<ResourceTable> overlay = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x00)
+            .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"false"))
+            .build();
+
+    ResourceTable finalTable;
+    TableMergerOptions tableMergerOptions;
+    tableMergerOptions.autoAddOverlay = false;
+    TableMerger merger(mContext.get(), &finalTable, tableMergerOptions);
+
+    ASSERT_TRUE(merger.merge({}, base.get()));
+    ASSERT_TRUE(merger.mergeOverlay({}, overlay.get()));
+
+    BinaryPrimitive* foo = test::getValue<BinaryPrimitive>(&finalTable, u"@com.app.a:bool/foo");
+    ASSERT_NE(nullptr, foo);
+    EXPECT_EQ(0x0u, foo->value.data);
+}
+
+TEST_F(TableMergerTest, MergeAddResourceFromOverlay) {
+    std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x7f)
+            .setSymbolState(u"@bool/foo", {}, SymbolState::kUndefined)
+            .build();
+    std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x7f)
+            .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+            .build();
+
+    ResourceTable finalTable;
+    TableMerger merger(mContext.get(), &finalTable, TableMergerOptions{});
+
+    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
+}
+
+TEST_F(TableMergerTest, MergeAddResourceFromOverlayWithAutoAddOverlay) {
+    std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x7f)
+            .build();
+    std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x7f)
+            .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+            .build();
+
+    ResourceTable finalTable;
+    TableMergerOptions options;
+    options.autoAddOverlay = true;
+    TableMerger merger(mContext.get(), &finalTable, options);
+
+    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
+}
+
+TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
+    std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x7f)
+            .build();
+    std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
+            .setPackageId(u"", 0x7f)
+            .addValue(u"@bool/foo", ResourceUtils::tryParseBool(u"true"))
+            .build();
+
+    ResourceTable finalTable;
+    TableMergerOptions options;
+    options.autoAddOverlay = false;
+    TableMerger merger(mContext.get(), &finalTable, options);
+
+    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_FALSE(merger.mergeOverlay({}, tableB.get()));
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 6fdaebb..51e2dd4 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -22,7 +22,7 @@
 #include "ResourceTable.h"
 #include "ResourceUtils.h"
 #include "ValueVisitor.h"
-
+#include "io/File.h"
 #include "process/IResourceTableConsumer.h"
 #include "util/StringPiece.h"
 
@@ -87,6 +87,22 @@
     return getValueForConfig<T>(table, resName, {});
 }
 
+class TestFile : public io::IFile {
+private:
+    Source mSource;
+
+public:
+    TestFile(const StringPiece& path) : mSource(path) {}
+
+    std::unique_ptr<io::IData> openAsData() override {
+        return {};
+    }
+
+    const Source& getSource() const override {
+        return mSource;
+    }
+};
+
 } // namespace test
 } // namespace aapt
 
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 46b5205..21e476f 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -447,6 +447,10 @@
         case Public_entry::kPublic:
             symbol.state = SymbolState::kPublic;
             break;
+
+        case Public_entry::kUndefined:
+            symbol.state = SymbolState::kUndefined;
+            break;
         }
 
         if (!mTable->setSymbolStateAllowMangled(name, resId, symbol, mContext->getDiagnostics())) {
diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h
index aa409ea..10a2803 100644
--- a/tools/aapt2/util/Maybe.h
+++ b/tools/aapt2/util/Maybe.h
@@ -285,6 +285,8 @@
 -> decltype(std::declval<T> == std::declval<U>) {
     if (a && b) {
         return a.value() == b.value();
+    } else if (!a && !b) {
+        return true;
     }
     return false;
 }
diff --git a/tools/aapt2/util/Maybe_test.cpp b/tools/aapt2/util/Maybe_test.cpp
index 9cca40e..5d42dc3 100644
--- a/tools/aapt2/util/Maybe_test.cpp
+++ b/tools/aapt2/util/Maybe_test.cpp
@@ -124,9 +124,12 @@
     Maybe<int> b = 1;
     Maybe<int> c;
 
+    Maybe<int> emptyA, emptyB;
+
     EXPECT_EQ(a, b);
     EXPECT_EQ(b, a);
     EXPECT_NE(a, c);
+    EXPECT_EQ(emptyA, emptyB);
 }
 
 } // namespace aapt
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index bd5335e..63411b0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1634,6 +1634,11 @@
     }
 
     @Override
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
+        // pass
+    }
+
+    @Override
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
             UserHandle user, BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -1804,24 +1809,24 @@
     }
 
     @Override
-    public Context createDeviceEncryptedContext(Context context) {
+    public Context createDeviceEncryptedStorageContext() {
         // pass
         return null;
     }
 
     @Override
-    public Context createCredentialEncryptedContext(Context context) {
+    public Context createCredentialEncryptedStorageContext() {
         // pass
         return null;
     }
 
     @Override
-    public boolean isDeviceEncrypted() {
+    public boolean isDeviceEncryptedStorage() {
         return false;
     }
 
     @Override
-    public boolean isCredentialEncrypted() {
+    public boolean isCredentialEncryptedStorage() {
         return false;
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 26f9000..d797eec 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -42,10 +42,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
  *
@@ -72,8 +68,12 @@
         BridgeContext context = getContext();
         drawableResource = context.getRenderResources().resolveResValue(drawableResource);
 
-        if (drawableResource == null ||
-                drawableResource.getResourceType() != ResourceType.DRAWABLE) {
+        if (drawableResource == null) {
+            return Status.ERROR_NOT_A_DRAWABLE.createResult();
+        }
+
+        ResourceType resourceType = drawableResource.getResourceType();
+        if (resourceType != ResourceType.DRAWABLE && resourceType != ResourceType.MIPMAP) {
             return Status.ERROR_NOT_A_DRAWABLE.createResult();
         }
 
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
index 0ddfa77..a0b5a6e 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
@@ -296,7 +296,7 @@
         sbuf.append("serviceType:").append(mServiceType);
         sbuf.append(" status:").append(Status.toString(mStatus));
         sbuf.append(" srcAddr:").append(mDevice.deviceAddress);
-        sbuf.append(" data:").append(mData);
+        sbuf.append(" data:").append(Arrays.toString(mData));
         return sbuf.toString();
     }