Merge "Interval tree for SpannableStringBuilder"
diff --git a/Android.mk b/Android.mk
index 2d0d1f7..a20798d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -202,6 +202,7 @@
 	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/IPermissionController.aidl \
+	core/java/android/os/IProcessInfoService.aidl \
 	core/java/android/os/IPowerManager.aidl \
 	core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/ISchedulingPolicyService.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index bd3227f..c35f332 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -227,6 +227,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/widget/ILockSettingsObserver.java)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/SystemUI_intermediates/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/Keyguard_intermediates/)
+$(call add-clean-step, rm -f $(OUT_DIR)/target/product/*/system/framework/android.policy.jar)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 13b1d11..118223c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -529,6 +529,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
+    field public static final int end = 16843997; // 0x10104dd
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -1014,6 +1015,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16843995; // 0x10104db
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1127,6 +1129,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
+    field public static final int start = 16843996; // 0x10104dc
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -1316,6 +1319,8 @@
     field public static final int topRightRadius = 16843178; // 0x10101aa
     field public static final int touchscreenBlocksFocus = 16843919; // 0x101048f
     field public static final int track = 16843631; // 0x101036f
+    field public static final int trackTint = 16843993; // 0x10104d9
+    field public static final int trackTintMode = 16843994; // 0x10104da
     field public static final int transcriptMode = 16843008; // 0x1010100
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
@@ -1407,6 +1412,7 @@
     field public static final int windowExitTransition = 16843832; // 0x1010438
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
+    field public static final int windowHasLightStatusBar = 16843998; // 0x10104de
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
@@ -2080,6 +2086,21 @@
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_Material = 16974372; // 0x1030224
+    field public static final int Theme_Material_DayNight = 16974548; // 0x10302d4
+    field public static final int Theme_Material_DayNight_DarkActionBar = 16974549; // 0x10302d5
+    field public static final int Theme_Material_DayNight_Dialog = 16974550; // 0x10302d6
+    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974556; // 0x10302dc
+    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974557; // 0x10302dd
+    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974551; // 0x10302d7
+    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974552; // 0x10302d8
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974553; // 0x10302d9
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974554; // 0x10302da
+    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974555; // 0x10302db
+    field public static final int Theme_Material_DayNight_NoActionBar = 16974558; // 0x10302de
+    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974559; // 0x10302df
+    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974560; // 0x10302e0
+    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974561; // 0x10302e1
+    field public static final int Theme_Material_DayNight_Panel = 16974562; // 0x10302e2
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -3914,6 +3935,46 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AssistData implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.app.AssistData getAssistData(android.os.Bundle);
+    method public void getWindowAt(int, android.app.AssistData.ViewNode);
+    method public int getWindowCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ASSIST_KEY = "android:assist";
+    field public static final android.os.Parcelable.Creator<android.app.AssistData> CREATOR;
+  }
+
+  public static class AssistData.ViewNode {
+    ctor public AssistData.ViewNode();
+    method public void getChildAt(int, android.app.AssistData.ViewNode);
+    method public int getChildCount();
+    method public java.lang.String getClassName();
+    method public java.lang.String getContentDescription();
+    method public android.os.Bundle getExtras();
+    method public int getHeight();
+    method public java.lang.String getHint();
+    method public int getLeft();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public java.lang.String getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public int getTop();
+    method public int getVisibility();
+    method public int getWidth();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActivated();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isLongClickable();
+    method public boolean isSelected();
+  }
+
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -4767,6 +4828,37 @@
     method public android.app.Notification.Builder setWhen(long);
   }
 
+  public static final class Notification.CarExtender implements android.app.Notification.Extender {
+    ctor public Notification.CarExtender();
+    ctor public Notification.CarExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.app.Notification.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.app.Notification.CarExtender setColor(int);
+    method public android.app.Notification.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.app.Notification.CarExtender setUnreadConversation(android.app.Notification.CarExtender.UnreadConversation);
+  }
+
+  public static class Notification.CarExtender.Builder {
+    ctor public Notification.CarExtender.Builder(java.lang.String);
+    method public android.app.Notification.CarExtender.Builder addMessage(java.lang.String);
+    method public android.app.Notification.CarExtender.UnreadConversation build();
+    method public android.app.Notification.CarExtender.Builder setLatestTimestamp(long);
+    method public android.app.Notification.CarExtender.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.app.Notification.CarExtender.Builder setReplyAction(android.app.PendingIntent, android.app.RemoteInput);
+  }
+
+  public static class Notification.CarExtender.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
@@ -5453,6 +5545,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -11907,10 +12000,15 @@
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+    method public int addLayer(android.graphics.drawable.Drawable);
     method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
+    method public int findIndexByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
+    method public int getLayerGravity(int);
+    method public int getLayerHeight(int);
+    method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
     method public int getPaddingMode();
@@ -11918,9 +12016,13 @@
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(int, android.graphics.drawable.Drawable);
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
+    method public void setLayerGravity(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerSize(int, int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
@@ -12661,11 +12763,14 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_COMPENSATION_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AE_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AWB_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AWB_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
@@ -12684,6 +12789,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW;
@@ -12703,6 +12809,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> SENSOR_INFO_LENS_SHADING_APPLIED;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE;
@@ -12713,8 +12820,10 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SHADING_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
@@ -12794,6 +12903,7 @@
     field public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3; // 0x3
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2; // 0x2
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4; // 0x4
+    field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2; // 0x2
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0; // 0x0
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1; // 0x1
     field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
@@ -12901,13 +13011,16 @@
     field public static final int LENS_STATE_STATIONARY = 0; // 0x0
     field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int NOISE_REDUCTION_MODE_MINIMAL = 3; // 0x3
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; // 0x4
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
     field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3
@@ -12957,7 +13070,11 @@
     field public static final int SYNC_MAX_LATENCY_UNKNOWN = -1; // 0xffffffff
     field public static final int TONEMAP_MODE_CONTRAST_CURVE = 0; // 0x0
     field public static final int TONEMAP_MODE_FAST = 1; // 0x1
+    field public static final int TONEMAP_MODE_GAMMA_VALUE = 3; // 0x3
     field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int TONEMAP_MODE_PRESET_CURVE = 4; // 0x4
+    field public static final int TONEMAP_PRESET_CURVE_REC709 = 1; // 0x1
+    field public static final int TONEMAP_PRESET_CURVE_SRGB = 0; // 0x0
   }
 
   public class CaptureFailure {
@@ -13013,6 +13130,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_FRAME_DURATION;
@@ -13024,7 +13142,9 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureRequest.Builder {
@@ -13090,6 +13210,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH;
     field public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
@@ -13111,7 +13232,9 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER;
     field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureResult.Key {
@@ -14129,6 +14252,7 @@
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
     method public boolean isSpeakerphoneOn();
+    method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
     method public deprecated boolean isWiredHeadsetOn();
     method public void loadSoundEffects();
@@ -14147,8 +14271,8 @@
     method public void setRingerMode(int);
     method public deprecated void setRouting(int, int, int);
     method public void setSpeakerphoneOn(boolean);
-    method public void setStreamMute(int, boolean);
-    method public void setStreamSolo(int, boolean);
+    method public deprecated void setStreamMute(int, boolean);
+    method public deprecated void setStreamSolo(int, boolean);
     method public void setStreamVolume(int, int, int);
     method public deprecated void setVibrateSetting(int, int);
     method public deprecated void setWiredHeadsetOn(boolean);
@@ -14166,8 +14290,11 @@
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
+    field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
     field public static final int ADJUST_SAME = 0; // 0x0
+    field public static final int ADJUST_TOGGLE_MUTE = 101; // 0x65
+    field public static final int ADJUST_UNMUTE = 100; // 0x64
     field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
@@ -17578,7 +17705,6 @@
     method public static javax.net.SocketFactory getDefault(int);
     method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
     method public java.lang.String[] getDefaultCipherSuites();
-    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
     method public byte[] getNpnSelectedProtocol(java.net.Socket);
     method public java.lang.String[] getSupportedCipherSuites();
@@ -21789,6 +21915,7 @@
     field public static final int KITKAT_WATCH = 20; // 0x14
     field public static final int LOLLIPOP = 21; // 0x15
     field public static final int LOLLIPOP_MR1 = 22; // 0x16
+    field public static final int MNC = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -23177,6 +23304,7 @@
   public final class PrintAttributes implements android.os.Parcelable {
     method public int describeContents();
     method public int getColorMode();
+    method public int getDuplexMode();
     method public android.print.PrintAttributes.MediaSize getMediaSize();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public android.print.PrintAttributes.Resolution getResolution();
@@ -23184,12 +23312,16 @@
     field public static final int COLOR_MODE_COLOR = 2; // 0x2
     field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR;
+    field public static final int DUPLEX_MODE_LONG_EDGE = 2; // 0x2
+    field public static final int DUPLEX_MODE_NONE = 1; // 0x1
+    field public static final int DUPLEX_MODE_SHORT_EDGE = 4; // 0x4
   }
 
   public static final class PrintAttributes.Builder {
     ctor public PrintAttributes.Builder();
     method public android.print.PrintAttributes build();
     method public android.print.PrintAttributes.Builder setColorMode(int);
+    method public android.print.PrintAttributes.Builder setDuplexMode(int);
     method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
     method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
     method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
@@ -23407,6 +23539,7 @@
     method public int describeContents();
     method public int getColorModes();
     method public android.print.PrintAttributes getDefaults();
+    method public int getDuplexModes();
     method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
@@ -23420,6 +23553,7 @@
     method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
     method public android.print.PrinterCapabilitiesInfo build();
     method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
+    method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int);
     method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
   }
 
@@ -24616,6 +24750,7 @@
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final java.lang.String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
   }
 
   public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
@@ -24930,6 +25065,7 @@
     method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
     field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
     field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
+    field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -28559,8 +28695,65 @@
 
 package android.telecom {
 
+  public class PhoneAccount implements android.os.Parcelable {
+    method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+    method public android.graphics.drawable.Drawable createIconDrawable(android.content.Context);
+    method public int describeContents();
+    method public android.telecom.PhoneAccountHandle getAccountHandle();
+    method public android.net.Uri getAddress();
+    method public int getCapabilities();
+    method public int getHighlightColor();
+    method public android.graphics.Bitmap getIconBitmap();
+    method public java.lang.String getIconPackageName();
+    method public int getIconResId();
+    method public int getIconTint();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.CharSequence getShortDescription();
+    method public android.net.Uri getSubscriptionAddress();
+    method public java.util.List<java.lang.String> getSupportedUriSchemes();
+    method public boolean hasCapabilities(int);
+    method public boolean supportsUriScheme(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    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 android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+    field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
+    field public static final int NO_ICON_TINT = 0; // 0x0
+    field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
+    field public static final java.lang.String SCHEME_SIP = "sip";
+    field public static final java.lang.String SCHEME_TEL = "tel";
+    field public static final java.lang.String SCHEME_VOICEMAIL = "voicemail";
+  }
+
+  public static class PhoneAccount.Builder {
+    ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+    ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
+    method public android.telecom.PhoneAccount build();
+    method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
+    method public android.telecom.PhoneAccount.Builder setCapabilities(int);
+    method public android.telecom.PhoneAccount.Builder setHighlightColor(int);
+    method public android.telecom.PhoneAccount.Builder setIcon(android.content.Context, int);
+    method public android.telecom.PhoneAccount.Builder setIcon(java.lang.String, int);
+    method public android.telecom.PhoneAccount.Builder setIcon(android.content.Context, int, int);
+    method public android.telecom.PhoneAccount.Builder setIcon(java.lang.String, int, int);
+    method public android.telecom.PhoneAccount.Builder setIcon(android.graphics.Bitmap);
+    method public android.telecom.PhoneAccount.Builder setShortDescription(java.lang.CharSequence);
+    method public android.telecom.PhoneAccount.Builder setSubscriptionAddress(android.net.Uri);
+    method public android.telecom.PhoneAccount.Builder setSupportedUriSchemes(java.util.List<java.lang.String>);
+  }
+
+  public class PhoneAccountHandle implements android.os.Parcelable {
+    ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
+    method public int describeContents();
+    method public android.content.ComponentName getComponentName();
+    method public java.lang.String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR;
+  }
+
   public class TelecomManager {
     method public void cancelMissedCallsNotification();
+    method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
     method public boolean isInCall();
     method public void showInCallScreen(boolean);
@@ -28569,7 +28762,10 @@
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
+    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -28578,6 +28774,34 @@
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
   }
 
+  public class VideoProfile implements android.os.Parcelable {
+    ctor public VideoProfile(int);
+    ctor public VideoProfile(int, int);
+    method public int describeContents();
+    method public int getQuality();
+    method public int getVideoState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile> CREATOR;
+    field public static final int QUALITY_DEFAULT = 4; // 0x4
+    field public static final int QUALITY_HIGH = 1; // 0x1
+    field public static final int QUALITY_LOW = 3; // 0x3
+    field public static final int QUALITY_MEDIUM = 2; // 0x2
+  }
+
+  public static class VideoProfile.VideoState {
+    ctor public VideoProfile.VideoState();
+    method public static boolean isAudioOnly(int);
+    method public static boolean isBidirectional(int);
+    method public static boolean isPaused(int);
+    method public static boolean isReceptionEnabled(int);
+    method public static boolean isTransmissionEnabled(int);
+    field public static final int AUDIO_ONLY = 0; // 0x0
+    field public static final int BIDIRECTIONAL = 3; // 0x3
+    field public static final int PAUSED = 4; // 0x4
+    field public static final int RX_ENABLED = 2; // 0x2
+    field public static final int TX_ENABLED = 1; // 0x1
+  }
+
 }
 
 package android.telephony {
@@ -28771,6 +28995,7 @@
 
   public class PhoneNumberUtils {
     ctor public PhoneNumberUtils();
+    method public static void addPhoneTtsSpan(android.text.Spannable, int, int);
     method public static java.lang.String calledPartyBCDFragmentToString(byte[], int, int);
     method public static java.lang.String calledPartyBCDToString(byte[], int, int);
     method public static boolean compare(java.lang.String, java.lang.String);
@@ -28788,6 +29013,8 @@
     method public static java.lang.String formatNumberToRFC3966(java.lang.String, java.lang.String);
     method public static deprecated int getFormatTypeForLocale(java.util.Locale);
     method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
+    method public static android.text.style.TtsSpan getPhoneTtsSpan(java.lang.String);
+    method public static java.lang.CharSequence getPhoneTtsSpannable(java.lang.CharSequence);
     method public static java.lang.String getStrippedReversed(java.lang.String);
     method public static final boolean is12Key(char);
     method public static final boolean isDialable(char);
@@ -31834,6 +32061,7 @@
     method public boolean equals(android.util.DisplayMetrics);
     method public void setTo(android.util.DisplayMetrics);
     method public void setToDefaults();
+    field public static final int DENSITY_280 = 280; // 0x118
     field public static final int DENSITY_400 = 400; // 0x190
     field public static final int DENSITY_560 = 560; // 0x230
     field public static final int DENSITY_DEFAULT = 160; // 0xa0
@@ -32403,6 +32631,7 @@
     method public java.lang.Object getTag();
     method public abstract java.lang.CharSequence getTitle();
     method public boolean getTitleOptionalHint();
+    method public int getType();
     method public abstract void invalidate();
     method public boolean isTitleOptional();
     method public abstract void setCustomView(android.view.View);
@@ -32412,6 +32641,9 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
+    method public void setType(int);
+    field public static final int TYPE_FLOATING = 1; // 0x1
+    field public static final int TYPE_PRIMARY = 0; // 0x0
   }
 
   public static abstract interface ActionMode.Callback {
@@ -33762,6 +33994,7 @@
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
+    method public java.lang.CharSequence getAccessibilityClassName();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public int getAccessibilityTraversalAfter();
@@ -33987,6 +34220,7 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onProvideAssistData(android.view.ViewAssistData, android.os.Bundle);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -34262,6 +34496,7 @@
     field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
     field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
     field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
+    field public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 8192; // 0x2000
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
@@ -34388,6 +34623,17 @@
     method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
   }
 
+  public abstract class ViewAssistData {
+    ctor public ViewAssistData();
+    method public abstract java.lang.CharSequence getHint();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract int getTextSelectionEnd();
+    method public abstract int getTextSelectionStart();
+    method public abstract void setHint(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence, int, int);
+  }
+
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
@@ -38415,6 +38661,8 @@
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
+    method public void setEnterTransition(android.transition.Transition);
+    method public void setExitTransition(android.transition.Transition);
     method public void setFocusable(boolean);
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
@@ -39016,7 +39264,11 @@
     method public java.lang.CharSequence getTextOn();
     method public android.graphics.drawable.Drawable getThumbDrawable();
     method public int getThumbTextPadding();
+    method public android.content.res.ColorStateList getThumbTintList();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public android.content.res.ColorStateList getTrackTintList();
+    method public android.graphics.PorterDuff.Mode getTrackTintMode();
     method public void onMeasure(int, int);
     method public void setShowText(boolean);
     method public void setSplitTrack(boolean);
@@ -39030,8 +39282,12 @@
     method public void setThumbDrawable(android.graphics.drawable.Drawable);
     method public void setThumbResource(int);
     method public void setThumbTextPadding(int);
+    method public void setThumbTintList(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
     method public void setTrackDrawable(android.graphics.drawable.Drawable);
     method public void setTrackResource(int);
+    method public void setTrackTintList(android.content.res.ColorStateList);
+    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
diff --git a/api/removed.txt b/api/removed.txt
index 1b69ee8..9322973 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -6,6 +6,14 @@
 
 }
 
+package android.net {
+
+  public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
+    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
+  }
+
+}
+
 package android.os {
 
   public final class PowerManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index 3063aaa..903c40c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -601,6 +601,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
+    field public static final int end = 16843997; // 0x10104dd
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -1086,6 +1087,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16843995; // 0x10104db
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1203,6 +1205,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
+    field public static final int start = 16843996; // 0x10104dc
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -1392,6 +1395,8 @@
     field public static final int topRightRadius = 16843178; // 0x10101aa
     field public static final int touchscreenBlocksFocus = 16843919; // 0x101048f
     field public static final int track = 16843631; // 0x101036f
+    field public static final int trackTint = 16843993; // 0x10104d9
+    field public static final int trackTintMode = 16843994; // 0x10104da
     field public static final int transcriptMode = 16843008; // 0x1010100
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
@@ -1483,6 +1488,7 @@
     field public static final int windowExitTransition = 16843832; // 0x1010438
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
+    field public static final int windowHasLightStatusBar = 16843998; // 0x10104de
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
@@ -2159,6 +2165,21 @@
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_Material = 16974372; // 0x1030224
+    field public static final int Theme_Material_DayNight = 16974548; // 0x10302d4
+    field public static final int Theme_Material_DayNight_DarkActionBar = 16974549; // 0x10302d5
+    field public static final int Theme_Material_DayNight_Dialog = 16974550; // 0x10302d6
+    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974556; // 0x10302dc
+    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974557; // 0x10302dd
+    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974551; // 0x10302d7
+    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974552; // 0x10302d8
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974553; // 0x10302d9
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974554; // 0x10302da
+    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974555; // 0x10302db
+    field public static final int Theme_Material_DayNight_NoActionBar = 16974558; // 0x10302de
+    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974559; // 0x10302df
+    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974560; // 0x10302e0
+    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974561; // 0x10302e1
+    field public static final int Theme_Material_DayNight_Panel = 16974562; // 0x10302e2
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -4004,6 +4025,46 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AssistData implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.app.AssistData getAssistData(android.os.Bundle);
+    method public void getWindowAt(int, android.app.AssistData.ViewNode);
+    method public int getWindowCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ASSIST_KEY = "android:assist";
+    field public static final android.os.Parcelable.Creator<android.app.AssistData> CREATOR;
+  }
+
+  public static class AssistData.ViewNode {
+    ctor public AssistData.ViewNode();
+    method public void getChildAt(int, android.app.AssistData.ViewNode);
+    method public int getChildCount();
+    method public java.lang.String getClassName();
+    method public java.lang.String getContentDescription();
+    method public android.os.Bundle getExtras();
+    method public int getHeight();
+    method public java.lang.String getHint();
+    method public int getLeft();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public java.lang.String getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public int getTop();
+    method public int getVisibility();
+    method public int getWidth();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActivated();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isLongClickable();
+    method public boolean isSelected();
+  }
+
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -4857,6 +4918,37 @@
     method public android.app.Notification.Builder setWhen(long);
   }
 
+  public static final class Notification.CarExtender implements android.app.Notification.Extender {
+    ctor public Notification.CarExtender();
+    ctor public Notification.CarExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.app.Notification.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.app.Notification.CarExtender setColor(int);
+    method public android.app.Notification.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.app.Notification.CarExtender setUnreadConversation(android.app.Notification.CarExtender.UnreadConversation);
+  }
+
+  public static class Notification.CarExtender.Builder {
+    ctor public Notification.CarExtender.Builder(java.lang.String);
+    method public android.app.Notification.CarExtender.Builder addMessage(java.lang.String);
+    method public android.app.Notification.CarExtender.UnreadConversation build();
+    method public android.app.Notification.CarExtender.Builder setLatestTimestamp(long);
+    method public android.app.Notification.CarExtender.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.app.Notification.CarExtender.Builder setReplyAction(android.app.PendingIntent, android.app.RemoteInput);
+  }
+
+  public static class Notification.CarExtender.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
@@ -5334,6 +5426,7 @@
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clearWallpaper();
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -5354,6 +5447,7 @@
     method public void setDisplayPadding(android.graphics.Rect);
     method public void setResource(int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
+    method public boolean setWallpaperComponent(android.content.ComponentName);
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
@@ -5554,6 +5648,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -6422,6 +6517,8 @@
     method public java.lang.String getName();
     method public int getType();
     method public android.os.ParcelUuid[] getUuids();
+    method public boolean isConnected();
+    method public boolean isEncrypted();
     method public boolean setPairingConfirmation(boolean);
     method public boolean setPin(byte[]);
     method public void writeToParcel(android.os.Parcel, int);
@@ -7923,6 +8020,7 @@
     field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
+    field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
@@ -8021,6 +8119,7 @@
     field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -12175,10 +12274,15 @@
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+    method public int addLayer(android.graphics.drawable.Drawable);
     method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
+    method public int findIndexByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
+    method public int getLayerGravity(int);
+    method public int getLayerHeight(int);
+    method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
     method public int getPaddingMode();
@@ -12186,9 +12290,13 @@
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(int, android.graphics.drawable.Drawable);
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
+    method public void setLayerGravity(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerSize(int, int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
@@ -12729,6 +12837,7 @@
     field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
     field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+    field public static final java.lang.String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -12751,6 +12860,7 @@
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
+    field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
   }
 
   public class SensorEvent {
@@ -12929,11 +13039,14 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_COMPENSATION_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AE_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AWB_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AWB_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
@@ -12952,6 +13065,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW;
@@ -12971,6 +13085,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> SENSOR_INFO_LENS_SHADING_APPLIED;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE;
@@ -12981,8 +13096,10 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SHADING_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
@@ -13062,6 +13179,7 @@
     field public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3; // 0x3
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2; // 0x2
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4; // 0x4
+    field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2; // 0x2
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0; // 0x0
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1; // 0x1
     field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
@@ -13169,13 +13287,16 @@
     field public static final int LENS_STATE_STATIONARY = 0; // 0x0
     field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int NOISE_REDUCTION_MODE_MINIMAL = 3; // 0x3
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; // 0x4
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
     field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3
@@ -13225,7 +13346,11 @@
     field public static final int SYNC_MAX_LATENCY_UNKNOWN = -1; // 0xffffffff
     field public static final int TONEMAP_MODE_CONTRAST_CURVE = 0; // 0x0
     field public static final int TONEMAP_MODE_FAST = 1; // 0x1
+    field public static final int TONEMAP_MODE_GAMMA_VALUE = 3; // 0x3
     field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int TONEMAP_MODE_PRESET_CURVE = 4; // 0x4
+    field public static final int TONEMAP_PRESET_CURVE_REC709 = 1; // 0x1
+    field public static final int TONEMAP_PRESET_CURVE_SRGB = 0; // 0x0
   }
 
   public class CaptureFailure {
@@ -13281,6 +13406,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_FRAME_DURATION;
@@ -13292,7 +13418,9 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureRequest.Builder {
@@ -13358,6 +13486,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH;
     field public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
@@ -13379,7 +13508,9 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER;
     field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureResult.Key {
@@ -15107,6 +15238,7 @@
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
     method public boolean isSpeakerphoneOn();
+    method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
     method public deprecated boolean isWiredHeadsetOn();
     method public void loadSoundEffects();
@@ -15128,8 +15260,8 @@
     method public void setRingerMode(int);
     method public deprecated void setRouting(int, int, int);
     method public void setSpeakerphoneOn(boolean);
-    method public void setStreamMute(int, boolean);
-    method public void setStreamSolo(int, boolean);
+    method public deprecated void setStreamMute(int, boolean);
+    method public deprecated void setStreamSolo(int, boolean);
     method public void setStreamVolume(int, int, int);
     method public deprecated void setVibrateSetting(int, int);
     method public deprecated void setWiredHeadsetOn(boolean);
@@ -15148,8 +15280,11 @@
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
+    field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
     field public static final int ADJUST_SAME = 0; // 0x0
+    field public static final int ADJUST_TOGGLE_MUTE = 101; // 0x65
+    field public static final int ADJUST_UNMUTE = 100; // 0x64
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
@@ -18838,7 +18973,6 @@
     method public static javax.net.SocketFactory getDefault(int);
     method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
     method public java.lang.String[] getDefaultCipherSuites();
-    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
     method public byte[] getNpnSelectedProtocol(java.net.Socket);
     method public java.lang.String[] getSupportedCipherSuites();
@@ -23368,6 +23502,7 @@
     field public static final int KITKAT_WATCH = 20; // 0x14
     field public static final int LOLLIPOP = 21; // 0x15
     field public static final int LOLLIPOP_MR1 = 22; // 0x16
+    field public static final int MNC = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -24766,6 +24901,7 @@
   public final class PrintAttributes implements android.os.Parcelable {
     method public int describeContents();
     method public int getColorMode();
+    method public int getDuplexMode();
     method public android.print.PrintAttributes.MediaSize getMediaSize();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public android.print.PrintAttributes.Resolution getResolution();
@@ -24773,12 +24909,16 @@
     field public static final int COLOR_MODE_COLOR = 2; // 0x2
     field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR;
+    field public static final int DUPLEX_MODE_LONG_EDGE = 2; // 0x2
+    field public static final int DUPLEX_MODE_NONE = 1; // 0x1
+    field public static final int DUPLEX_MODE_SHORT_EDGE = 4; // 0x4
   }
 
   public static final class PrintAttributes.Builder {
     ctor public PrintAttributes.Builder();
     method public android.print.PrintAttributes build();
     method public android.print.PrintAttributes.Builder setColorMode(int);
+    method public android.print.PrintAttributes.Builder setDuplexMode(int);
     method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
     method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
     method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
@@ -24996,6 +25136,7 @@
     method public int describeContents();
     method public int getColorModes();
     method public android.print.PrintAttributes getDefaults();
+    method public int getDuplexModes();
     method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
@@ -25009,6 +25150,7 @@
     method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
     method public android.print.PrinterCapabilitiesInfo build();
     method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
+    method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int);
     method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
   }
 
@@ -26205,6 +26347,7 @@
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final java.lang.String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
   }
 
   public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
@@ -26519,6 +26662,7 @@
     method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
     field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
     field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
+    field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -27220,6 +27364,7 @@
     field public static final java.lang.String SHOW_PROCESSES = "show_processes";
     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
     field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_global_version";
+    field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
     field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
@@ -30397,6 +30542,7 @@
     method public final int getState();
     method public final android.telecom.StatusHints getStatusHints();
     method public final boolean isRingbackRequested();
+    method protected void notifyConferenceStarted();
     method public void onAbort();
     method public void onAnswer();
     method public void onAudioStateChanged(android.telecom.AudioState);
@@ -30422,6 +30568,7 @@
     method public final void setDisconnected(android.telecom.DisconnectCause);
     method public final void setInitialized();
     method public final void setInitializing();
+    method public final void setNextPostDialChar(char);
     method public final void setOnHold();
     method public final void setPostDialWait(java.lang.String);
     method public final void setRingbackRequested(boolean);
@@ -30561,10 +30708,14 @@
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
     method public boolean supportsUriScheme(java.lang.String);
+    method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
+    field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+    field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_ICON_TINT = 0; // 0x0
@@ -30577,7 +30728,9 @@
   public static class PhoneAccount.Builder {
     ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
     ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
+    method public android.telecom.PhoneAccount.Builder addSupportedUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount build();
+    method public android.telecom.PhoneAccount.Builder setAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
     method public android.telecom.PhoneAccount.Builder setCapabilities(int);
     method public android.telecom.PhoneAccount.Builder setHighlightColor(int);
@@ -30593,9 +30746,11 @@
 
   public class PhoneAccountHandle implements android.os.Parcelable {
     ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
+    ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String, android.os.UserHandle);
     method public int describeContents();
     method public android.content.ComponentName getComponentName();
     method public java.lang.String getId();
+    method public android.os.UserHandle getUserHandle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR;
   }
@@ -30731,6 +30886,7 @@
     field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -30739,6 +30895,34 @@
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
   }
 
+  public class VideoProfile implements android.os.Parcelable {
+    ctor public VideoProfile(int);
+    ctor public VideoProfile(int, int);
+    method public int describeContents();
+    method public int getQuality();
+    method public int getVideoState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile> CREATOR;
+    field public static final int QUALITY_DEFAULT = 4; // 0x4
+    field public static final int QUALITY_HIGH = 1; // 0x1
+    field public static final int QUALITY_LOW = 3; // 0x3
+    field public static final int QUALITY_MEDIUM = 2; // 0x2
+  }
+
+  public static class VideoProfile.VideoState {
+    ctor public VideoProfile.VideoState();
+    method public static boolean isAudioOnly(int);
+    method public static boolean isBidirectional(int);
+    method public static boolean isPaused(int);
+    method public static boolean isReceptionEnabled(int);
+    method public static boolean isTransmissionEnabled(int);
+    field public static final int AUDIO_ONLY = 0; // 0x0
+    field public static final int BIDIRECTIONAL = 3; // 0x3
+    field public static final int PAUSED = 4; // 0x4
+    field public static final int RX_ENABLED = 2; // 0x2
+    field public static final int TX_ENABLED = 1; // 0x1
+  }
+
 }
 
 package android.telephony {
@@ -30932,6 +31116,7 @@
 
   public class PhoneNumberUtils {
     ctor public PhoneNumberUtils();
+    method public static void addPhoneTtsSpan(android.text.Spannable, int, int);
     method public static java.lang.String calledPartyBCDFragmentToString(byte[], int, int);
     method public static java.lang.String calledPartyBCDToString(byte[], int, int);
     method public static boolean compare(java.lang.String, java.lang.String);
@@ -30949,6 +31134,8 @@
     method public static java.lang.String formatNumberToRFC3966(java.lang.String, java.lang.String);
     method public static deprecated int getFormatTypeForLocale(java.util.Locale);
     method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
+    method public static android.text.style.TtsSpan getPhoneTtsSpan(java.lang.String);
+    method public static java.lang.CharSequence getPhoneTtsSpannable(java.lang.CharSequence);
     method public static java.lang.String getStrippedReversed(java.lang.String);
     method public static final boolean is12Key(char);
     method public static final boolean isDialable(char);
@@ -34033,6 +34220,7 @@
     method public boolean equals(android.util.DisplayMetrics);
     method public void setTo(android.util.DisplayMetrics);
     method public void setToDefaults();
+    field public static final int DENSITY_280 = 280; // 0x118
     field public static final int DENSITY_400 = 400; // 0x190
     field public static final int DENSITY_560 = 560; // 0x230
     field public static final int DENSITY_DEFAULT = 160; // 0xa0
@@ -34602,6 +34790,7 @@
     method public java.lang.Object getTag();
     method public abstract java.lang.CharSequence getTitle();
     method public boolean getTitleOptionalHint();
+    method public int getType();
     method public abstract void invalidate();
     method public boolean isTitleOptional();
     method public abstract void setCustomView(android.view.View);
@@ -34611,6 +34800,9 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
+    method public void setType(int);
+    field public static final int TYPE_FLOATING = 1; // 0x1
+    field public static final int TYPE_PRIMARY = 0; // 0x0
   }
 
   public static abstract interface ActionMode.Callback {
@@ -35961,6 +36153,7 @@
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
+    method public java.lang.CharSequence getAccessibilityClassName();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public int getAccessibilityTraversalAfter();
@@ -36186,6 +36379,7 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onProvideAssistData(android.view.ViewAssistData, android.os.Bundle);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -36461,6 +36655,7 @@
     field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
     field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
     field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
+    field public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 8192; // 0x2000
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
@@ -36587,6 +36782,17 @@
     method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
   }
 
+  public abstract class ViewAssistData {
+    ctor public ViewAssistData();
+    method public abstract java.lang.CharSequence getHint();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract int getTextSelectionEnd();
+    method public abstract int getTextSelectionStart();
+    method public abstract void setHint(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence, int, int);
+  }
+
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
@@ -37285,8 +37491,10 @@
     method public java.lang.String debug(java.lang.String);
     method public int describeContents();
     method public final java.lang.CharSequence getTitle();
+    method public final long getUserActivityTimeout();
     method public static boolean mayUseInputMethod(int);
     method public final void setTitle(java.lang.CharSequence);
+    method public final void setUserActivityTimeout(long);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALPHA_CHANGED = 128; // 0x80
     field public static final int ANIMATION_CHANGED = 16; // 0x10
@@ -40910,6 +41118,8 @@
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
+    method public void setEnterTransition(android.transition.Transition);
+    method public void setExitTransition(android.transition.Transition);
     method public void setFocusable(boolean);
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
@@ -41511,7 +41721,11 @@
     method public java.lang.CharSequence getTextOn();
     method public android.graphics.drawable.Drawable getThumbDrawable();
     method public int getThumbTextPadding();
+    method public android.content.res.ColorStateList getThumbTintList();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public android.content.res.ColorStateList getTrackTintList();
+    method public android.graphics.PorterDuff.Mode getTrackTintMode();
     method public void onMeasure(int, int);
     method public void setShowText(boolean);
     method public void setSplitTrack(boolean);
@@ -41525,8 +41739,12 @@
     method public void setThumbDrawable(android.graphics.drawable.Drawable);
     method public void setThumbResource(int);
     method public void setThumbTextPadding(int);
+    method public void setThumbTintList(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
     method public void setTrackDrawable(android.graphics.drawable.Drawable);
     method public void setTrackResource(int);
+    method public void setTrackTintList(android.content.res.ColorStateList);
+    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 1b69ee8..9322973 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,6 +6,14 @@
 
 }
 
+package android.net {
+
+  public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
+    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
+  }
+
+}
+
 package android.os {
 
   public final class PowerManager {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 2a0ed90..62081ee 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -132,10 +132,12 @@
                 "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack split <STACK_ID> <v|h> [INTENT]\n" +
                 "       am stack list\n" +
                 "       am stack info <STACK_ID>\n" +
-                "       am lock-task <TASK_ID>\n" +
-                "       am lock-task stop\n" +
+                "       am task lock <TASK_ID>\n" +
+                "       am task lock stop\n" +
+                "       am task resizeable <TASK_ID> [true|false]\n" +
                 "       am get-config\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
@@ -244,13 +246,24 @@
                 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
                 "   bottom (false) of <STACK_ID>.\n" +
                 "\n" +
-                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>" +
+                ".\n" +
+                "\n" +
+                "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally" +
+                "   starting the new stack with [INTENT] if specified. If [INTENT] isn't" +
+                "   specified and the current stack has more than one task, then the top task" +
+                "   of the current task will be moved to the new stack. Command will also force" +
+                "   all current tasks in both stacks to be resizeable." +
                 "\n" +
                 "am stack list: list all of the activity stacks and their sizes.\n" +
                 "\n" +
                 "am stack info: display the information about activity stack <STACK_ID>.\n" +
                 "\n" +
-                "am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
+                "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
+                "\n" +
+                "am task lock stop: end the current task lock\n" +
+                "\n" +
+                "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" +
                 "\n" +
                 "am get-config: retrieve the configuration and any recent configurations\n" +
                 "  of the device\n" +
@@ -351,8 +364,8 @@
             runStopUser();
         } else if (op.equals("stack")) {
             runStack();
-        } else if (op.equals("lock-task")) {
-            runLockTask();
+        } else if (op.equals("task")) {
+            runTask();
         } else if (op.equals("get-config")) {
             runGetConfig();
         } else {
@@ -1682,6 +1695,8 @@
             runStackList();
         } else if (op.equals("info")) {
             runStackInfo();
+        } else if (op.equals("split")) {
+            runStackSplit();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
@@ -1735,6 +1750,22 @@
         int right = Integer.valueOf(rightStr);
         String bottomStr = nextArgRequired();
         int bottom = Integer.valueOf(bottomStr);
+        if (left < 0) {
+            System.err.println("Error: bad left arg: " + leftStr);
+            return;
+        }
+        if (top < 0) {
+            System.err.println("Error: bad top arg: " + topStr);
+            return;
+        }
+        if (right <= 0) {
+            System.err.println("Error: bad right arg: " + rightStr);
+            return;
+        }
+        if (bottom <= 0) {
+            System.err.println("Error: bad bottom arg: " + bottomStr);
+            return;
+        }
 
         try {
             mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
@@ -1762,7 +1793,77 @@
         }
     }
 
-    private void runLockTask() throws Exception {
+    private void runStackSplit() throws Exception {
+        final int stackId = Integer.valueOf(nextArgRequired());
+        final String splitDirection = nextArgRequired();
+        Intent intent = null;
+        try {
+            intent = makeIntent(UserHandle.USER_CURRENT);
+        } catch (IllegalArgumentException e) {
+            // no intent supplied.
+        }
+
+        try {
+            final StackInfo currentStackInfo = mAm.getStackInfo(stackId);
+            // Calculate bounds for new and current stack.
+            final Rect currentStackBounds = new Rect(currentStackInfo.bounds);
+            final Rect newStackBounds = new Rect(currentStackInfo.bounds);
+            if ("v".equals(splitDirection)) {
+                currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX();
+            } else if ("h".equals(splitDirection)) {
+                currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY();
+            } else {
+                showError("Error: unknown split direction '" + splitDirection + "'");
+                return;
+            }
+
+            // Create new stack
+            IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId);
+            if (container == null) {
+                showError("Error: Unable to create new stack...");
+            }
+
+            final int newStackId = container.getStackId();
+
+            if (intent != null) {
+                container.startActivity(intent);
+            } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) {
+                // Move top task over to new stack
+                mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1],
+                        newStackId, true);
+            }
+
+            final StackInfo newStackInfo = mAm.getStackInfo(newStackId);
+
+            // Make all tasks in the stacks resizeable.
+            for (int taskId : currentStackInfo.taskIds) {
+                mAm.setTaskResizeable(taskId, true);
+            }
+
+            for (int taskId : newStackInfo.taskIds) {
+                mAm.setTaskResizeable(taskId, true);
+            }
+
+            // Resize stacks
+            mAm.resizeStack(currentStackInfo.stackId, currentStackBounds);
+            mAm.resizeStack(newStackInfo.stackId, newStackBounds);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runTask() throws Exception {
+        String op = nextArgRequired();
+        if (op.equals("lock")) {
+            runTaskLock();
+        } else if (op.equals("resizeable")) {
+            runTaskResizeable();
+        } else {
+            showError("Error: unknown command '" + op + "'");
+            return;
+        }
+    }
+
+    private void runTaskLock() throws Exception {
         String taskIdStr = nextArgRequired();
         try {
             if (taskIdStr.equals("stop")) {
@@ -1777,6 +1878,18 @@
         }
     }
 
+    private void runTaskResizeable() throws Exception {
+        final String taskIdStr = nextArgRequired();
+        final int taskId = Integer.valueOf(taskIdStr);
+        final String resizeableStr = nextArgRequired();
+        final boolean resizeable = Boolean.valueOf(resizeableStr);
+
+        try {
+            mAm.setTaskResizeable(taskId, resizeable);
+        } catch (RemoteException e) {
+        }
+    }
+
     private List<Configuration> getRecentConfigurations(int days) {
         IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
                     Context.USAGE_STATS_SERVICE));
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 27a03b6..5f7a17d 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -54,10 +54,6 @@
         int action, in Bundle arguments, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, long threadId);
 
-    boolean computeClickPointInScreen(int accessibilityWindowId, long accessibilityNodeId,
-        int interactionId, IAccessibilityInteractionConnectionCallback callback,
-        long threadId);
-
     AccessibilityWindowInfo getWindow(int windowId);
 
     List<AccessibilityWindowInfo> getWindows();
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
index 2c7d502..26a61ae 100644
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -80,8 +80,11 @@
               } else if (lineIndex == 1) {
                   tokenIndex = mTokenizer.nextToken(line, 0);
                   if (tokenIndex != -1) {
-                      mCardDescription = line.substring(tokenIndex);
-                      mIsUsb = mCardDescription.contains(kUsbCardKeyStr);
+                      int keyIndex = line.indexOf(kUsbCardKeyStr);
+                      mIsUsb = keyIndex != -1;
+                      if (mIsUsb) {
+                          mCardDescription = line.substring(tokenIndex, keyIndex - 1);
+                      }
                   }
             }
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 74c468d..aa1c70e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -27,7 +27,6 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.app.ToolbarActionBar;
-import com.android.internal.policy.PolicyManager;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
@@ -84,6 +83,7 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
@@ -743,6 +743,7 @@
     final FragmentManagerImpl mFragments = new FragmentManagerImpl();
     final FragmentContainer mContainer = new FragmentContainer() {
         @Override
+        @Nullable
         public View findViewById(int id) {
             return Activity.this.findViewById(id);
         }
@@ -1534,13 +1535,17 @@
      * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
      * application.  You can override this method to place into the bundle anything
      * you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part
-     * of the assist Intent.  The default implementation does nothing.
+     * of the assist Intent.  The default implementation automatically generates a
+     * {@link AssistData} from your activity and places it in to the Bundle; if you
+     * don't want your UI reported to the assistant, don't call this default
+     * implementation.
      *
      * <p>This function will be called after any global assist callbacks that had
      * been registered with {@link Application#registerOnProvideAssistDataListener
      * Application.registerOnProvideAssistDataListener}.
      */
     public void onProvideAssistData(Bundle data) {
+        data.putParcelable(AssistData.ASSIST_KEY, new AssistData(this));
     }
 
     /**
@@ -2064,6 +2069,7 @@
      *
      * @return The view if found or null otherwise.
      */
+    @Nullable
     public View findViewById(int id) {
         return getWindow().findViewById(id);
     }
@@ -3226,7 +3232,9 @@
      * Programmatically closes the most recently opened context menu, if showing.
      */
     public void closeContextMenu() {
-        mWindow.closePanel(Window.FEATURE_CONTEXT_MENU);
+        if (mWindow.hasFeature(Window.FEATURE_CONTEXT_MENU)) {
+            mWindow.closePanel(Window.FEATURE_CONTEXT_MENU);
+        }
     }
 
     /**
@@ -5923,7 +5931,7 @@
 
         mFragments.attachActivity(this, mContainer, null);
 
-        mWindow = PolicyManager.makeNewWindow(this);
+        mWindow = new PhoneWindow(this);
         mWindow.setCallback(this);
         mWindow.setOnWindowDismissedCallback(this);
         mWindow.getLayoutInflater().setPrivateFactory(this);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7a636db..c6ffef6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -256,6 +256,9 @@
     /** @hide User operation call: given user id is the current user, can't be stopped. */
     public static final int USER_OP_IS_CURRENT = -2;
 
+    /** @hide Process does not exist. */
+    public static final int PROCESS_STATE_NONEXISTENT = -1;
+
     /** @hide Process is a persistent system process. */
     public static final int PROCESS_STATE_PERSISTENT = 0;
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 379fe11..47f57ea 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -766,6 +766,14 @@
             return true;
         }
 
+        case GET_FOCUSED_STACK_ID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int focusedStackId = getFocusedStackId();
+            reply.writeNoException();
+            reply.writeInt(focusedStackId);
+            return true;
+        }
+
         case REGISTER_TASK_STACK_LISTENER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -2292,6 +2300,15 @@
             return true;
         }
 
+        case SET_TASK_RESIZEABLE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            boolean resizeable = (data.readInt() == 1) ? true : false;
+            setTaskResizeable(taskId, resizeable);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_TASK_DESCRIPTION_ICON_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String filename = data.readString();
@@ -3290,6 +3307,18 @@
         reply.recycle();
     }
     @Override
+    public int getFocusedStackId() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_FOCUSED_STACK_ID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int focusedStackId = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return focusedStackId;
+    }
+    @Override
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -5382,6 +5411,19 @@
     }
 
     @Override
+    public void setTaskResizeable(int taskId, boolean resizeable) throws  RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        data.writeInt(resizeable ? 1 : 0);
+        mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index de3c95c..d781863 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -294,6 +294,8 @@
         Configuration newConfig;
         Configuration createdConfig;
         Configuration overrideConfig;
+        // Used for consolidating configs before sending on to Activity.
+        private Configuration tmpConfig = new Configuration();
         ActivityClientRecord nextIdle;
 
         ProfilerInfo profilerInfo;
@@ -557,6 +559,15 @@
         int requestType;
     }
 
+    static final class ActivityConfigChangeData {
+        final IBinder activityToken;
+        final Configuration overrideConfig;
+        public ActivityConfigChangeData(IBinder token, Configuration config) {
+            activityToken = token;
+            overrideConfig = config;
+        }
+    }
+
     private native void dumpGraphicsInfo(FileDescriptor fd);
 
     private class ApplicationThread extends ApplicationThreadNative {
@@ -888,15 +899,19 @@
                     sticky, sendingUser);
         }
 
+        @Override
         public void scheduleLowMemory() {
             sendMessage(H.LOW_MEMORY, null);
         }
 
         @Override
-        public void scheduleActivityConfigurationChanged(IBinder token) {
-            sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
+        public void scheduleActivityConfigurationChanged(
+                IBinder token, Configuration overrideConfig) {
+            sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED,
+                    new ActivityConfigChangeData(token, overrideConfig));
         }
 
+        @Override
         public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
             sendMessage(H.PROFILER_CONTROL, profilerInfo, start ? 1 : 0, profileType);
         }
@@ -1456,7 +1471,7 @@
                     break;
                 case ACTIVITY_CONFIGURATION_CHANGED:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
-                    handleActivityConfigurationChanged((IBinder)msg.obj);
+                    handleActivityConfigurationChanged((ActivityConfigChangeData)msg.obj);
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case PROFILER_CONTROL:
@@ -3099,10 +3114,14 @@
             if (!r.activity.mFinished && willBeVisible
                     && r.activity.mDecor != null && !r.hideForNow) {
                 if (r.newConfig != null) {
+                    r.tmpConfig.setTo(r.newConfig);
+                    if (r.overrideConfig != null) {
+                        r.tmpConfig.updateFrom(r.overrideConfig);
+                    }
                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
-                            + r.activityInfo.name + " with newConfig " + r.newConfig);
-                    performConfigurationChanged(r.activity, r.newConfig);
-                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
+                            + r.activityInfo.name + " with newConfig " + r.tmpConfig);
+                    performConfigurationChanged(r.activity, r.tmpConfig);
+                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
                     r.newConfig = null;
                 }
                 if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
@@ -3431,10 +3450,14 @@
                     }
                 }
                 if (r.newConfig != null) {
+                    r.tmpConfig.setTo(r.newConfig);
+                    if (r.overrideConfig != null) {
+                        r.tmpConfig.updateFrom(r.overrideConfig);
+                    }
                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating activity vis "
-                            + r.activityInfo.name + " with new config " + r.newConfig);
-                    performConfigurationChanged(r.activity, r.newConfig);
-                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
+                            + r.activityInfo.name + " with new config " + r.tmpConfig);
+                    performConfigurationChanged(r.activity, r.tmpConfig);
+                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
                     r.newConfig = null;
                 }
             } else {
@@ -4164,16 +4187,21 @@
         }
     }
 
-    final void handleActivityConfigurationChanged(IBinder token) {
-        ActivityClientRecord r = mActivities.get(token);
+    final void handleActivityConfigurationChanged(ActivityConfigChangeData data) {
+        ActivityClientRecord r = mActivities.get(data.activityToken);
         if (r == null || r.activity == null) {
             return;
         }
 
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
                 + r.activityInfo.name);
-        
-        performConfigurationChanged(r.activity, mCompatConfiguration);
+
+        r.tmpConfig.setTo(mCompatConfiguration);
+        if (data.overrideConfig != null) {
+            r.overrideConfig = data.overrideConfig;
+            r.tmpConfig.updateFrom(data.overrideConfig);
+        }
+        performConfigurationChanged(r.activity, r.tmpConfig);
 
         freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));
 
@@ -4404,10 +4432,16 @@
             if (cacheDir != null) {
                 // Provide a usable directory for temporary files
                 System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-    
-                setupGraphicsSupport(data.info, cacheDir);
             } else {
-                Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
+                Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory");
+            }
+
+            // Use codeCacheDir to store generated/compiled graphics code
+            final File codeCacheDir = appContext.getCodeCacheDir();
+            if (codeCacheDir != null) {
+                setupGraphicsSupport(data.info, codeCacheDir);
+            } else {
+                Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
             }
         }
 
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 967e97e..d808c8b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -63,6 +63,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
+import android.os.SystemProperties;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
@@ -287,7 +288,12 @@
         // depending on what the current runtime's instruction set is.
         if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
             final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
-            final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+
+            // Get the instruction set that the libraries of secondary Abi is supported.
+            // In presence of a native bridge this might be different than the one secondary Abi used.
+            String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+            final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
+            secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
 
             // If the runtimeIsa is the same as the primary isa, then we do nothing.
             // Everything will be set up correctly because info.nativeLibraryDir will
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 349b66d..b6989ab 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -409,7 +409,11 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder b = data.readStrongBinder();
-            scheduleActivityConfigurationChanged(b);
+            Configuration overrideConfig = null;
+            if (data.readInt() != 0) {
+                overrideConfig = Configuration.CREATOR.createFromParcel(data);
+            }
+            scheduleActivityConfigurationChanged(b, overrideConfig);
             return true;
         }
 
@@ -1116,6 +1120,7 @@
         data.recycle();
     }
 
+    @Override
     public final void scheduleLowMemory() throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1124,15 +1129,24 @@
         data.recycle();
     }
 
-    public final void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException {
+    @Override
+    public final void scheduleActivityConfigurationChanged(
+            IBinder token, Configuration overrideConfig) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
+        if (overrideConfig != null) {
+            data.writeInt(1);
+            overrideConfig.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
         mRemote.transact(SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 
+    @Override
     public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType)
             throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/AssistData.java b/core/java/android/app/AssistData.java
new file mode 100644
index 0000000..8d3d348
--- /dev/null
+++ b/core/java/android/app/AssistData.java
@@ -0,0 +1,519 @@
+/*
+ * 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.app;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAssistData;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+import android.widget.Checkable;
+
+import java.util.ArrayList;
+
+/**
+ * Assist data automatically created by the platform's implementation
+ * of {@link Activity#onProvideAssistData}.  Retrieve it from the assist
+ * data with {@link #getAssistData(android.os.Bundle)}.
+ */
+final public class AssistData implements Parcelable {
+    static final String TAG = "AssistData";
+
+    /**
+     * Key name this data structure is stored in the Bundle generated by
+     * {@link Activity#onProvideAssistData}.
+     */
+    public static final String ASSIST_KEY = "android:assist";
+
+    final ArrayList<ViewNodeImpl> mRootViews = new ArrayList<>();
+
+    ViewAssistDataImpl mTmpViewAssistDataImpl = new ViewAssistDataImpl();
+    Bundle mTmpExtras = new Bundle();
+
+    final static class ViewAssistDataImpl extends ViewAssistData {
+        CharSequence mText;
+        int mTextSelectionStart = -1;
+        int mTextSelectionEnd = -1;
+        CharSequence mHint;
+
+        @Override
+        public void setText(CharSequence text) {
+            mText = text;
+            mTextSelectionStart = mTextSelectionEnd = -1;
+        }
+
+        @Override
+        public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+            mText = text;
+            mTextSelectionStart = selectionStart;
+            mTextSelectionEnd = selectionEnd;
+        }
+
+        @Override
+        public void setHint(CharSequence hint) {
+            mHint = hint;
+        }
+
+        @Override
+        public CharSequence getText() {
+            return mText;
+        }
+
+        @Override
+        public int getTextSelectionStart() {
+            return mTextSelectionStart;
+        }
+
+        @Override
+        public int getTextSelectionEnd() {
+            return mTextSelectionEnd;
+        }
+
+        @Override
+        public CharSequence getHint() {
+            return mHint;
+        }
+    }
+
+    final static class ViewNodeTextImpl {
+        final String mText;
+        final int mTextSelectionStart;
+        final int mTextSelectionEnd;
+        final String mHint;
+
+        ViewNodeTextImpl(ViewAssistDataImpl data) {
+            mText = data.mText != null ? data.mText.toString() : null;
+            mTextSelectionStart = data.mTextSelectionStart;
+            mTextSelectionEnd = data.mTextSelectionEnd;
+            mHint = data.mHint != null ? data.mHint.toString() : null;
+        }
+
+        ViewNodeTextImpl(Parcel in) {
+            mText = in.readString();
+            mTextSelectionStart = in.readInt();
+            mTextSelectionEnd = in.readInt();
+            mHint = in.readString();
+        }
+
+        void writeToParcel(Parcel out) {
+            out.writeString(mText);
+            out.writeInt(mTextSelectionStart);
+            out.writeInt(mTextSelectionEnd);
+            out.writeString(mHint);
+        }
+    }
+
+    final static class ViewNodeImpl {
+        final int mX;
+        final int mY;
+        final int mScrollX;
+        final int mScrollY;
+        final int mWidth;
+        final int mHeight;
+
+        static final int FLAGS_DISABLED = 0x00000001;
+        static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
+        static final int FLAGS_FOCUSABLE = 0x00000010;
+        static final int FLAGS_FOCUSED = 0x00000020;
+        static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x04000000;
+        static final int FLAGS_SELECTED = 0x00000040;
+        static final int FLAGS_ACTIVATED = 0x40000000;
+        static final int FLAGS_CHECKABLE = 0x00000100;
+        static final int FLAGS_CHECKED = 0x00000200;
+        static final int FLAGS_CLICKABLE = 0x00004000;
+        static final int FLAGS_LONG_CLICKABLE = 0x00200000;
+
+        final int mFlags;
+
+        final String mClassName;
+        final String mContentDescription;
+
+        final ViewNodeTextImpl mText;
+        final Bundle mExtras;
+
+        final ViewNodeImpl[] mChildren;
+
+        ViewNodeImpl(AssistData assistData, View view, int left, int top,
+                CharSequence contentDescription) {
+            mX = left;
+            mY = top;
+            mScrollX = view.getScrollX();
+            mScrollY = view.getScrollY();
+            mWidth = view.getWidth();
+            mHeight = view.getHeight();
+            int flags = view.getVisibility();
+            if (!view.isEnabled()) {
+                flags |= FLAGS_DISABLED;
+            }
+            if (!view.isClickable()) {
+                flags |= FLAGS_CLICKABLE;
+            }
+            if (!view.isFocusable()) {
+                flags |= FLAGS_FOCUSABLE;
+            }
+            if (!view.isFocused()) {
+                flags |= FLAGS_FOCUSED;
+            }
+            if (!view.isAccessibilityFocused()) {
+                flags |= FLAGS_ACCESSIBILITY_FOCUSED;
+            }
+            if (!view.isSelected()) {
+                flags |= FLAGS_SELECTED;
+            }
+            if (!view.isActivated()) {
+                flags |= FLAGS_ACTIVATED;
+            }
+            if (!view.isLongClickable()) {
+                flags |= FLAGS_LONG_CLICKABLE;
+            }
+            if (view instanceof Checkable) {
+                flags |= FLAGS_CHECKABLE;
+                if (((Checkable)view).isChecked()) {
+                    flags |= FLAGS_CHECKED;
+                }
+            }
+            mFlags = flags;
+            mClassName = view.getAccessibilityClassName().toString();
+            mContentDescription = contentDescription != null ? contentDescription.toString() : null;
+            final ViewAssistDataImpl viewData = assistData.mTmpViewAssistDataImpl;
+            final Bundle extras = assistData.mTmpExtras;
+            view.onProvideAssistData(viewData, extras);
+            if (viewData.mText != null || viewData.mHint != null) {
+                mText = new ViewNodeTextImpl(viewData);
+                assistData.mTmpViewAssistDataImpl = new ViewAssistDataImpl();
+            } else {
+                mText = null;
+            }
+            if (!extras.isEmpty()) {
+                mExtras = extras;
+                assistData.mTmpExtras = new Bundle();
+            } else {
+                mExtras = null;
+            }
+            if (view instanceof ViewGroup) {
+                ViewGroup vg = (ViewGroup)view;
+                final int NCHILDREN = vg.getChildCount();
+                if (NCHILDREN > 0) {
+                    mChildren = new ViewNodeImpl[NCHILDREN];
+                    for (int i=0; i<NCHILDREN; i++) {
+                        mChildren[i] = new ViewNodeImpl(assistData, vg.getChildAt(i));
+                    }
+                } else {
+                    mChildren = null;
+                }
+            } else {
+                mChildren = null;
+            }
+        }
+
+        ViewNodeImpl(AssistData assistData, View view) {
+            this(assistData, view, view.getLeft(), view.getTop(), view.getContentDescription());
+        }
+
+        ViewNodeImpl(Parcel in) {
+            mX = in.readInt();
+            mY = in.readInt();
+            mScrollX = in.readInt();
+            mScrollY = in.readInt();
+            mWidth = in.readInt();
+            mHeight = in.readInt();
+            mFlags = in.readInt();
+            mClassName = in.readString();
+            mContentDescription = in.readString();
+            if (in.readInt() != 0) {
+                mText = new ViewNodeTextImpl(in);
+            } else {
+                mText = null;
+            }
+            mExtras = in.readBundle();
+            final int NCHILDREN = in.readInt();
+            if (NCHILDREN > 0) {
+                mChildren = new ViewNodeImpl[NCHILDREN];
+                for (int i=0; i<NCHILDREN; i++) {
+                    mChildren[i] = new ViewNodeImpl(in);
+                }
+            } else {
+                mChildren = null;
+            }
+        }
+
+        void writeToParcel(Parcel out) {
+            out.writeInt(mX);
+            out.writeInt(mY);
+            out.writeInt(mScrollX);
+            out.writeInt(mScrollY);
+            out.writeInt(mWidth);
+            out.writeInt(mHeight);
+            out.writeInt(mFlags);
+            out.writeString(mClassName);
+            out.writeString(mContentDescription);
+            if (mText != null) {
+                out.writeInt(1);
+                mText.writeToParcel(out);
+            } else {
+                out.writeInt(0);
+            }
+            out.writeBundle(mExtras);
+            if (mChildren != null) {
+                final int NCHILDREN = mChildren.length;
+                out.writeInt(NCHILDREN);
+                for (int i=0; i<NCHILDREN; i++) {
+                    mChildren[i].writeToParcel(out);
+                }
+            } else {
+                out.writeInt(0);
+            }
+        }
+    }
+
+    /**
+     * Provides access to information about a single view in the assist data.
+     */
+    static public class ViewNode {
+        ViewNodeImpl mImpl;
+
+        public ViewNode() {
+        }
+
+        public int getLeft() {
+            return mImpl.mX;
+        }
+
+        public int getTop() {
+            return mImpl.mY;
+        }
+
+        public int getScrollX() {
+            return mImpl.mScrollX;
+        }
+
+        public int getScrollY() {
+            return mImpl.mScrollY;
+        }
+
+        public int getWidth() {
+            return mImpl.mWidth;
+        }
+
+        public int getHeight() {
+            return mImpl.mHeight;
+        }
+
+        public int getVisibility() {
+            return mImpl.mFlags&ViewNodeImpl.FLAGS_VISIBILITY_MASK;
+        }
+
+        public boolean isEnabled() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_DISABLED) == 0;
+        }
+
+        public boolean isClickable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_CLICKABLE) != 0;
+        }
+
+        public boolean isFocusable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSABLE) != 0;
+        }
+
+        public boolean isFocused() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSED) != 0;
+        }
+
+        public boolean isAccessibilityFocused() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+        }
+
+        public boolean isCheckable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKABLE) != 0;
+        }
+
+        public boolean isChecked() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKED) != 0;
+        }
+
+        public boolean isSelected() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_SELECTED) != 0;
+        }
+
+        public boolean isActivated() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACTIVATED) != 0;
+        }
+
+        public boolean isLongClickable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_LONG_CLICKABLE) != 0;
+        }
+
+        public String getClassName() {
+            return mImpl.mClassName;
+        }
+
+        public String getContentDescription() {
+            return mImpl.mContentDescription;
+        }
+
+        public String getText() {
+            return mImpl.mText != null ? mImpl.mText.mText : null;
+        }
+
+        public int getTextSelectionStart() {
+            return mImpl.mText != null ? mImpl.mText.mTextSelectionStart : -1;
+        }
+
+        public int getTextSelectionEnd() {
+            return mImpl.mText != null ? mImpl.mText.mTextSelectionEnd : -1;
+        }
+
+        public String getHint() {
+            return mImpl.mText != null ? mImpl.mText.mHint : null;
+        }
+
+        public Bundle getExtras() {
+            return mImpl.mExtras;
+        }
+
+        public int getChildCount() {
+            return mImpl.mChildren != null ? mImpl.mChildren.length : 0;
+        }
+
+        public void getChildAt(int index, ViewNode outNode) {
+            outNode.mImpl = mImpl.mChildren[index];
+        }
+    }
+
+    AssistData(Activity activity) {
+        ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
+                activity.getActivityToken());
+        for (int i=0; i<views.size(); i++) {
+            ViewRootImpl root = views.get(i);
+            View view = root.getView();
+            Rect rect = new Rect();
+            view.getBoundsOnScreen(rect);
+            CharSequence title = root.getTitle();
+            mRootViews.add(new ViewNodeImpl(this, view, rect.left, rect.top,
+                    title != null ? title : view.getContentDescription()));
+        }
+    }
+
+    AssistData(Parcel in) {
+        final int N = in.readInt();
+        for (int i=0; i<N; i++) {
+            mRootViews.add(new ViewNodeImpl(in));
+        }
+        //dump();
+    }
+
+    void dump() {
+        ViewNode node = new ViewNode();
+        final int N = getWindowCount();
+        for (int i=0; i<N; i++) {
+            Log.i(TAG, "Window #" + i + ":");
+            getWindowAt(i, node);
+            dump("  ", node);
+        }
+    }
+
+    void dump(String prefix, ViewNode node) {
+        Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+                + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
+        int scrollX = node.getScrollX();
+        int scrollY = node.getScrollY();
+        if (scrollX != 0 || scrollY != 0) {
+            Log.i(TAG, prefix + "  Scroll: " + scrollX + "," + scrollY);
+        }
+        String contentDescription = node.getContentDescription();
+        if (contentDescription != null) {
+            Log.i(TAG, prefix + "  Content description: " + contentDescription);
+        }
+        String text = node.getText();
+        if (text != null) {
+            Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
+                    + node.getTextSelectionEnd() + "): " + text);
+        }
+        String hint = node.getHint();
+        if (hint != null) {
+            Log.i(TAG, prefix + "  Hint: " + hint);
+        }
+        Bundle extras = node.getExtras();
+        if (extras != null) {
+            Log.i(TAG, prefix + "  Extras: " + extras);
+        }
+        final int NCHILDREN = node.getChildCount();
+        if (NCHILDREN > 0) {
+            Log.i(TAG, prefix + "  Children:");
+            String cprefix = prefix + "    ";
+            ViewNode cnode = new ViewNode();
+            for (int i=0; i<NCHILDREN; i++) {
+                node.getChildAt(i, cnode);
+                dump(cprefix, cnode);
+            }
+        }
+    }
+
+    /**
+     * Retrieve the framework-generated AssistData that is stored within
+     * the Bundle filled in by {@link Activity#onProvideAssistData}.
+     */
+    public static AssistData getAssistData(Bundle assistBundle) {
+        return assistBundle.getParcelable(ASSIST_KEY);
+    }
+
+    /**
+     * Return the number of window contents that have been collected in this assist data.
+     */
+    public int getWindowCount() {
+        return mRootViews.size();
+    }
+
+    /**
+     * Return the root view for one of the windows in the assist data.
+     * @param index Which window to retrieve, may be 0 to {@link #getWindowCount()}-1.
+     * @param outNode Node in which to place the window's root view.
+     */
+    public void getWindowAt(int index, ViewNode outNode) {
+        outNode.mImpl = mRootViews.get(index);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        int start = out.dataPosition();
+        final int N = mRootViews.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            mRootViews.get(i).writeToParcel(out);
+        }
+        Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
+    }
+
+    public static final Parcelable.Creator<AssistData> CREATOR
+            = new Parcelable.Creator<AssistData>() {
+        public AssistData createFromParcel(Parcel in) {
+            return new AssistData(in);
+        }
+
+        public AssistData[] newArray(int size) {
+            return new AssistData[size];
+        }
+    };
+}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 39caf0b..6c78cab 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -24,7 +24,6 @@
 import android.service.persistentdata.PersistentDataBlockManager;
 
 import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.Preconditions;
 
 import android.bluetooth.BluetoothManager;
@@ -139,6 +138,7 @@
 import android.view.DisplayAdjustments;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
+import android.view.PhoneLayoutInflater;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
@@ -235,7 +235,6 @@
     private final Resources mResources;
     private final Display mDisplay; // may be null if default display
     private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
-    private final Configuration mOverrideConfiguration;
 
     private final boolean mRestricted;
 
@@ -480,7 +479,7 @@
 
         registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
+                    return new PhoneLayoutInflater(ctx.getOuterContext());
                 }});
 
         registerService(LOCATION_SERVICE, new ServiceFetcher() {
@@ -2149,7 +2148,7 @@
             final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
                     new UserHandle(UserHandle.getUserId(application.uid)), restricted,
-                    mDisplay, mOverrideConfiguration);
+                    mDisplay, null);
             if (c.mResources != null) {
                 return c;
             }
@@ -2172,14 +2171,14 @@
         final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
         if (packageName.equals("system") || packageName.equals("android")) {
             return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                    user, restricted, mDisplay, mOverrideConfiguration);
+                    user, restricted, mDisplay, null);
         }
 
         LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
         if (pi != null) {
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
-                    user, restricted, mDisplay, mOverrideConfiguration);
+                    user, restricted, mDisplay, null);
             if (c.mResources != null) {
                 return c;
             }
@@ -2207,7 +2206,7 @@
         }
 
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                mUser, mRestricted, display, mOverrideConfiguration);
+                mUser, mRestricted, display, null);
     }
 
     private int getDisplayId() {
@@ -2287,7 +2286,6 @@
         mPackageInfo = packageInfo;
         mResourcesManager = ResourcesManager.getInstance();
         mDisplay = display;
-        mOverrideConfiguration = overrideConfiguration;
 
         final int displayId = getDisplayId();
         CompatibilityInfo compatInfo = null;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 067073a..a3662b2 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,14 +16,14 @@
 
 package android.app;
 
-import android.content.pm.ApplicationInfo;
 import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PolicyManager;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -42,6 +42,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
@@ -134,14 +135,14 @@
 
     /**
      * Create a Dialog window that uses a custom dialog style.
-     * 
+     *
      * @param context The Context in which the Dialog should run. In particular, it
      *                uses the window manager and theme from this context to
      *                present its UI.
-     * @param theme A style resource describing the theme to use for the 
-     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style 
-     * and Theme Resources</a> for more information about defining and using 
-     * styles.  This theme is applied on top of the current theme in 
+     * @param theme A style resource describing the theme to use for the
+     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
+     * and Theme Resources</a> for more information about defining and using
+     * styles.  This theme is applied on top of the current theme in
      * <var>context</var>.  If 0, the default dialog theme will be used.
      */
     public Dialog(Context context, int theme) {
@@ -162,7 +163,7 @@
         }
 
         mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-        Window w = PolicyManager.makeNewWindow(mContext);
+        Window w = new PhoneWindow(mContext);
         mWindow = w;
         w.setCallback(this);
         w.setOnWindowDismissedCallback(this);
@@ -476,6 +477,7 @@
      * @param id the identifier of the view to find
      * @return The view with the given id or null.
      */
+    @Nullable
     public View findViewById(int id) {
         return mWindow.findViewById(id);
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index ab28d95..f319309 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2008,6 +2008,7 @@
         mChildFragmentManager = new FragmentManagerImpl();
         mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
             @Override
+            @Nullable
             public View findViewById(int id) {
                 if (mView == null) {
                     throw new IllegalStateException("Fragment does not have a view");
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ccceef4..afdc917 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -394,6 +395,7 @@
  * Callbacks from FragmentManagerImpl to its container.
  */
 interface FragmentContainer {
+    @Nullable
     public View findViewById(int id);
     public boolean hasView();
 }
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 52884f7..ff1175f 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -32,6 +32,7 @@
     void checkEmbeddedAllowed(in Intent intent);
     void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender);
     int getDisplayId();
+    int getStackId();
     boolean injectEvent(in InputEvent event);
     void release();
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index f152c6f..467c99a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -139,6 +139,7 @@
     public StackInfo getStackInfo(int stackId) throws RemoteException;
     public boolean isInHomeStack(int taskId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
+    public int getFocusedStackId() throws RemoteException;
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
     public ContentProviderHolder getContentProvider(IApplicationThread caller,
@@ -459,6 +460,7 @@
 
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
+    public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
 
     public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
@@ -800,4 +802,6 @@
     // Start of M transactions
     int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
     int CREATE_STACK_ON_DISPLAY = IBinder.FIRST_CALL_TRANSACTION+281;
+    int GET_FOCUSED_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+282;
+    int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f2c912e..3fb82f6 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -114,7 +114,8 @@
             int resultCode, String data, Bundle extras, boolean ordered,
             boolean sticky, int sendingUser, int processState) throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
-    void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
+    void scheduleActivityConfigurationChanged(IBinder token, Configuration overrideConfig)
+            throws RemoteException;
     void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType)
             throws RemoteException;
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b01f87e..83c6c2b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -45,6 +45,7 @@
 import android.util.SparseArray;
 import android.view.DisplayAdjustments;
 import android.view.Display;
+import android.os.SystemProperties;
 import dalvik.system.VMRuntime;
 
 import java.io.File;
@@ -156,7 +157,12 @@
         // depending on what the current runtime's instruction set is.
         if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
             final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
-            final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+
+            // Get the instruction set that the libraries of secondary Abi is supported.
+            // In presence of a native bridge this might be different than the one secondary Abi used.
+            String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+            final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
+            secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
 
             // If the runtimeIsa is the same as the primary isa, then we do nothing.
             // Everything will be set up correctly because info.nativeLibraryDir will
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 860b9cc..87e744c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5065,6 +5065,403 @@
     }
 
     /**
+     * <p>Helper class to add Android Auto extensions to notifications. To create a notification
+     * with car extensions:
+     *
+     * <ol>
+     *  <li>Create an {@link Notification.Builder}, setting any desired
+     *  properties.
+     *  <li>Create a {@link CarExtender}.
+     *  <li>Set car-specific properties using the {@code add} and {@code set} methods of
+     *  {@link CarExtender}.
+     *  <li>Call {@link Notification.Builder#extend(Notification.Extender)}
+     *  to apply the extensions to a notification.
+     * </ol>
+     *
+     * <pre class="prettyprint">
+     * Notification notification = new Notification.Builder(context)
+     *         ...
+     *         .extend(new CarExtender()
+     *                 .set*(...))
+     *         .build();
+     * </pre>
+     *
+     * <p>Car extensions can be accessed on an existing notification by using the
+     * {@code CarExtender(Notification)} constructor, and then using the {@code get} methods
+     * to access values.
+     */
+    public static final class CarExtender implements Extender {
+        private static final String TAG = "CarExtender";
+
+        private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
+        private static final String EXTRA_LARGE_ICON = "large_icon";
+        private static final String EXTRA_CONVERSATION = "car_conversation";
+        private static final String EXTRA_COLOR = "app_color";
+
+        private Bitmap mLargeIcon;
+        private UnreadConversation mUnreadConversation;
+        private int mColor = Notification.COLOR_DEFAULT;
+
+        /**
+         * Create a {@link CarExtender} with default options.
+         */
+        public CarExtender() {
+        }
+
+        /**
+         * Create a {@link CarExtender} from the CarExtender options of an existing Notification.
+         *
+         * @param notif The notification from which to copy options.
+         */
+        public CarExtender(Notification notif) {
+            Bundle carBundle = notif.extras == null ?
+                    null : notif.extras.getBundle(EXTRA_CAR_EXTENDER);
+            if (carBundle != null) {
+                mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
+                mColor = carBundle.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
+
+                Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
+                mUnreadConversation = UnreadConversation.getUnreadConversationFromBundle(b);
+            }
+        }
+
+        /**
+         * Apply car extensions to a notification that is being built. This is typically called by
+         * the {@link Notification.Builder#extend(Notification.Extender)}
+         * method of {@link Notification.Builder}.
+         */
+        @Override
+        public Notification.Builder extend(Notification.Builder builder) {
+            Bundle carExtensions = new Bundle();
+
+            if (mLargeIcon != null) {
+                carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
+            }
+            if (mColor != Notification.COLOR_DEFAULT) {
+                carExtensions.putInt(EXTRA_COLOR, mColor);
+            }
+
+            if (mUnreadConversation != null) {
+                Bundle b = mUnreadConversation.getBundleForUnreadConversation();
+                carExtensions.putBundle(EXTRA_CONVERSATION, b);
+            }
+
+            builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions);
+            return builder;
+        }
+
+        /**
+         * Sets the accent color to use when Android Auto presents the notification.
+         *
+         * Android Auto uses the color set with {@link Notification.Builder#setColor(int)}
+         * to accent the displayed notification. However, not all colors are acceptable in an
+         * automotive setting. This method can be used to override the color provided in the
+         * notification in such a situation.
+         */
+        public CarExtender setColor(int color) {
+            mColor = color;
+            return this;
+        }
+
+        /**
+         * Gets the accent color.
+         *
+         * @see setColor
+         */
+        public int getColor() {
+            return mColor;
+        }
+
+        /**
+         * Sets the large icon of the car notification.
+         *
+         * If no large icon is set in the extender, Android Auto will display the icon
+         * specified by {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap)}
+         *
+         * @param largeIcon The large icon to use in the car notification.
+         * @return This object for method chaining.
+         */
+        public CarExtender setLargeIcon(Bitmap largeIcon) {
+            mLargeIcon = largeIcon;
+            return this;
+        }
+
+        /**
+         * Gets the large icon used in this car notification, or null if no icon has been set.
+         *
+         * @return The large icon for the car notification.
+         * @see CarExtender#setLargeIcon
+         */
+        public Bitmap getLargeIcon() {
+            return mLargeIcon;
+        }
+
+        /**
+         * Sets the unread conversation in a message notification.
+         *
+         * @param unreadConversation The unread part of the conversation this notification conveys.
+         * @return This object for method chaining.
+         */
+        public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
+            mUnreadConversation = unreadConversation;
+            return this;
+        }
+
+        /**
+         * Returns the unread conversation conveyed by this notification.
+         * @see #setUnreadConversation(UnreadConversation)
+         */
+        public UnreadConversation getUnreadConversation() {
+            return mUnreadConversation;
+        }
+
+        /**
+         * A class which holds the unread messages from a conversation.
+         */
+        public static class UnreadConversation {
+            private static final String KEY_AUTHOR = "author";
+            private static final String KEY_TEXT = "text";
+            private static final String KEY_MESSAGES = "messages";
+            private static final String KEY_REMOTE_INPUT = "remote_input";
+            private static final String KEY_ON_REPLY = "on_reply";
+            private static final String KEY_ON_READ = "on_read";
+            private static final String KEY_PARTICIPANTS = "participants";
+            private static final String KEY_TIMESTAMP = "timestamp";
+
+            private final String[] mMessages;
+            private final RemoteInput mRemoteInput;
+            private final PendingIntent mReplyPendingIntent;
+            private final PendingIntent mReadPendingIntent;
+            private final String[] mParticipants;
+            private final long mLatestTimestamp;
+
+            UnreadConversation(String[] messages, RemoteInput remoteInput,
+                    PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
+                    String[] participants, long latestTimestamp) {
+                mMessages = messages;
+                mRemoteInput = remoteInput;
+                mReadPendingIntent = readPendingIntent;
+                mReplyPendingIntent = replyPendingIntent;
+                mParticipants = participants;
+                mLatestTimestamp = latestTimestamp;
+            }
+
+            /**
+             * Gets the list of messages conveyed by this notification.
+             */
+            public String[] getMessages() {
+                return mMessages;
+            }
+
+            /**
+             * Gets the remote input that will be used to convey the response to a message list, or
+             * null if no such remote input exists.
+             */
+            public RemoteInput getRemoteInput() {
+                return mRemoteInput;
+            }
+
+            /**
+             * Gets the pending intent that will be triggered when the user replies to this
+             * notification.
+             */
+            public PendingIntent getReplyPendingIntent() {
+                return mReplyPendingIntent;
+            }
+
+            /**
+             * Gets the pending intent that Android Auto will send after it reads aloud all messages
+             * in this object's message list.
+             */
+            public PendingIntent getReadPendingIntent() {
+                return mReadPendingIntent;
+            }
+
+            /**
+             * Gets the participants in the conversation.
+             */
+            public String[] getParticipants() {
+                return mParticipants;
+            }
+
+            /**
+             * Gets the firs participant in the conversation.
+             */
+            public String getParticipant() {
+                return mParticipants.length > 0 ? mParticipants[0] : null;
+            }
+
+            /**
+             * Gets the timestamp of the conversation.
+             */
+            public long getLatestTimestamp() {
+                return mLatestTimestamp;
+            }
+
+            Bundle getBundleForUnreadConversation() {
+                Bundle b = new Bundle();
+                String author = null;
+                if (mParticipants != null && mParticipants.length > 1) {
+                    author = mParticipants[0];
+                }
+                Parcelable[] messages = new Parcelable[mMessages.length];
+                for (int i = 0; i < messages.length; i++) {
+                    Bundle m = new Bundle();
+                    m.putString(KEY_TEXT, mMessages[i]);
+                    m.putString(KEY_AUTHOR, author);
+                    messages[i] = m;
+                }
+                b.putParcelableArray(KEY_MESSAGES, messages);
+                if (mRemoteInput != null) {
+                    b.putParcelable(KEY_REMOTE_INPUT, mRemoteInput);
+                }
+                b.putParcelable(KEY_ON_REPLY, mReplyPendingIntent);
+                b.putParcelable(KEY_ON_READ, mReadPendingIntent);
+                b.putStringArray(KEY_PARTICIPANTS, mParticipants);
+                b.putLong(KEY_TIMESTAMP, mLatestTimestamp);
+                return b;
+            }
+
+            static UnreadConversation getUnreadConversationFromBundle(Bundle b) {
+                if (b == null) {
+                    return null;
+                }
+                Parcelable[] parcelableMessages = b.getParcelableArray(KEY_MESSAGES);
+                String[] messages = null;
+                if (parcelableMessages != null) {
+                    String[] tmp = new String[parcelableMessages.length];
+                    boolean success = true;
+                    for (int i = 0; i < tmp.length; i++) {
+                        if (!(parcelableMessages[i] instanceof Bundle)) {
+                            success = false;
+                            break;
+                        }
+                        tmp[i] = ((Bundle) parcelableMessages[i]).getString(KEY_TEXT);
+                        if (tmp[i] == null) {
+                            success = false;
+                            break;
+                        }
+                    }
+                    if (success) {
+                        messages = tmp;
+                    } else {
+                        return null;
+                    }
+                }
+
+                PendingIntent onRead = b.getParcelable(KEY_ON_READ);
+                PendingIntent onReply = b.getParcelable(KEY_ON_REPLY);
+
+                RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT);
+
+                String[] participants = b.getStringArray(KEY_PARTICIPANTS);
+                if (participants == null || participants.length != 1) {
+                    return null;
+                }
+
+                return new UnreadConversation(messages,
+                        remoteInput,
+                        onReply,
+                        onRead,
+                        participants, b.getLong(KEY_TIMESTAMP));
+            }
+        };
+
+        /**
+         * Builder class for {@link CarExtender.UnreadConversation} objects.
+         */
+        public static class Builder {
+            private final List<String> mMessages = new ArrayList<String>();
+            private final String mParticipant;
+            private RemoteInput mRemoteInput;
+            private PendingIntent mReadPendingIntent;
+            private PendingIntent mReplyPendingIntent;
+            private long mLatestTimestamp;
+
+            /**
+             * Constructs a new builder for {@link CarExtender.UnreadConversation}.
+             *
+             * @param name The name of the other participant in the conversation.
+             */
+            public Builder(String name) {
+                mParticipant = name;
+            }
+
+            /**
+             * Appends a new unread message to the list of messages for this conversation.
+             *
+             * The messages should be added from oldest to newest.
+             *
+             * @param message The text of the new unread message.
+             * @return This object for method chaining.
+             */
+            public Builder addMessage(String message) {
+                mMessages.add(message);
+                return this;
+            }
+
+            /**
+             * Sets the pending intent and remote input which will convey the reply to this
+             * notification.
+             *
+             * @param pendingIntent The pending intent which will be triggered on a reply.
+             * @param remoteInput The remote input parcelable which will carry the reply.
+             * @return This object for method chaining.
+             *
+             * @see CarExtender.UnreadConversation#getRemoteInput
+             * @see CarExtender.UnreadConversation#getReplyPendingIntent
+             */
+            public Builder setReplyAction(
+                    PendingIntent pendingIntent, RemoteInput remoteInput) {
+                mRemoteInput = remoteInput;
+                mReplyPendingIntent = pendingIntent;
+
+                return this;
+            }
+
+            /**
+             * Sets the pending intent that will be sent once the messages in this notification
+             * are read.
+             *
+             * @param pendingIntent The pending intent to use.
+             * @return This object for method chaining.
+             */
+            public Builder setReadPendingIntent(PendingIntent pendingIntent) {
+                mReadPendingIntent = pendingIntent;
+                return this;
+            }
+
+            /**
+             * Sets the timestamp of the most recent message in an unread conversation.
+             *
+             * If a messaging notification has been posted by your application and has not
+             * yet been cancelled, posting a later notification with the same id and tag
+             * but without a newer timestamp may result in Android Auto not displaying a
+             * heads up notification for the later notification.
+             *
+             * @param timestamp The timestamp of the most recent message in the conversation.
+             * @return This object for method chaining.
+             */
+            public Builder setLatestTimestamp(long timestamp) {
+                mLatestTimestamp = timestamp;
+                return this;
+            }
+
+            /**
+             * Builds a new unread conversation object.
+             *
+             * @return The new unread conversation object.
+             */
+            public UnreadConversation build() {
+                String[] messages = mMessages.toArray(new String[mMessages.size()]);
+                String[] participants = { mParticipant };
+                return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent,
+                        mReadPendingIntent, participants, mLatestTimestamp);
+            }
+        }
+    }
+
+    /**
      * Get an array of Notification objects from a parcelable array bundle field.
      * Update the bundle to have a typed array so fetches in the future don't need
      * to do an array copy.
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 4427ce1..e617553 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.Nullable;
 import android.content.SharedPreferences;
 import android.os.FileUtils;
 import android.os.Looper;
@@ -217,7 +218,8 @@
         }
     }
 
-    public String getString(String key, String defValue) {
+    @Nullable
+    public String getString(String key, @Nullable String defValue) {
         synchronized (this) {
             awaitLoadedLocked();
             String v = (String)mMap.get(key);
@@ -225,7 +227,8 @@
         }
     }
 
-    public Set<String> getStringSet(String key, Set<String> defValues) {
+    @Nullable
+    public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
         synchronized (this) {
             awaitLoadedLocked();
             Set<String> v = (Set<String>) mMap.get(key);
@@ -303,13 +306,13 @@
         private final Map<String, Object> mModified = Maps.newHashMap();
         private boolean mClear = false;
 
-        public Editor putString(String key, String value) {
+        public Editor putString(String key, @Nullable String value) {
             synchronized (this) {
                 mModified.put(key, value);
                 return this;
             }
         }
-        public Editor putStringSet(String key, Set<String> values) {
+        public Editor putStringSet(String key, @Nullable Set<String> values) {
             synchronized (this) {
                 mModified.put(key,
                         (values == null) ? null : new HashSet<String>(values));
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0a255f7..0f6ce12 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -219,10 +219,9 @@
     }
 
     /**
-     * Returns the currently configured night mode.
-     *
-     * @return {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES}, or
-     *  {@link #MODE_NIGHT_AUTO}.  When an error occurred -1 is returned.
+     * @return the currently configured night mode. May be one of
+     *         {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES},
+     *         {@link #MODE_NIGHT_AUTO}, or -1 on error.
      */
     public int getNightMode() {
         if (mService != null) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8bfe6d3..90d84ee 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -994,6 +994,47 @@
     }
 
     /**
+     * Clear the wallpaper.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void clearWallpaper() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return;
+        }
+        try {
+            sGlobals.mService.clearWallpaper();
+        } catch (RemoteException e) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Set the live wallpaper.
+     *
+     * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
+     * permission.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean setWallpaperComponent(ComponentName name) {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return false;
+        }
+        try {
+            sGlobals.mService.setWallpaperComponent(name);
+            return true;
+        } catch (RemoteException e) {
+            // Ignore
+        }
+        return false;
+    }
+
+    /**
      * Set the position of the current wallpaper within any larger space, when
      * that wallpaper is visible behind the given window.  The X and Y offsets
      * are floating point numbers ranging from 0 to 1, representing where the
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index e9cce51..381d851 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -170,10 +170,10 @@
      * lock task mode from an authorized package.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
      * will describe the authorized package using lock task mode.
      *
-     * @see DevicePolicyManager#isLockTaskPermitted(String)
-     *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
+     *
+     * @see DevicePolicyManager#isLockTaskPermitted(String)
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LOCK_TASK_ENTERING
@@ -183,20 +183,19 @@
      * Action sent to a device administrator to notify that the device is exiting
      * lock task mode from an authorized package.
      *
-     * @see DevicePolicyManager#isLockTaskPermitted(String)
-     *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
+     *
+     * @see DevicePolicyManager#isLockTaskPermitted(String)
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LOCK_TASK_EXITING
             = "android.app.action.LOCK_TASK_EXITING";
 
     /**
-     * A boolean describing whether the device is currently entering or exiting
-     * lock task mode.
+     * A string containing the name of the package entering lock task mode.
      *
-     * @see #ACTION_LOCK_TASK_CHANGED
+     * @see #ACTION_LOCK_TASK_ENTERING
      */
     public static final String EXTRA_LOCK_TASK_PACKAGE =
             "android.app.extra.LOCK_TASK_PACKAGE";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 55c3960..318a314 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -332,6 +332,16 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
 
     /**
+     * A boolean extra indicating whether device encryption is required as part of Device Owner
+     * provisioning.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
+             "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+
+    /**
      * This MIME type is used for starting the Device Owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -361,7 +371,8 @@
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li></ul>
+     * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul>
      *
      * <p> When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -694,7 +705,7 @@
     public void setPasswordQuality(ComponentName admin, int quality) {
         if (mService != null) {
             try {
-                mService.setPasswordQuality(admin, quality, UserHandle.myUserId());
+                mService.setPasswordQuality(admin, quality);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -747,7 +758,7 @@
     public void setPasswordMinimumLength(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLength(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumLength(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -801,7 +812,7 @@
     public void setPasswordMinimumUpperCase(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumUpperCase(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumUpperCase(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -862,7 +873,7 @@
     public void setPasswordMinimumLowerCase(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLowerCase(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumLowerCase(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -922,7 +933,7 @@
     public void setPasswordMinimumLetters(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLetters(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumLetters(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -980,7 +991,7 @@
     public void setPasswordMinimumNumeric(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNumeric(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumNumeric(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1039,7 +1050,7 @@
     public void setPasswordMinimumSymbols(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumSymbols(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumSymbols(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1097,7 +1108,7 @@
     public void setPasswordMinimumNonLetter(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNonLetter(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumNonLetter(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1157,7 +1168,7 @@
     public void setPasswordHistoryLength(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordHistoryLength(admin, length, UserHandle.myUserId());
+                mService.setPasswordHistoryLength(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1189,7 +1200,7 @@
     public void setPasswordExpirationTimeout(ComponentName admin, long timeout) {
         if (mService != null) {
             try {
-                mService.setPasswordExpirationTimeout(admin, timeout, UserHandle.myUserId());
+                mService.setPasswordExpirationTimeout(admin, timeout);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1334,7 +1345,7 @@
     public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
         if (mService != null) {
             try {
-                mService.setMaximumFailedPasswordsForWipe(admin, num, UserHandle.myUserId());
+                mService.setMaximumFailedPasswordsForWipe(admin, num);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1418,7 +1429,7 @@
     public boolean resetPassword(String password, int flags) {
         if (mService != null) {
             try {
-                return mService.resetPassword(password, flags, UserHandle.myUserId());
+                return mService.resetPassword(password, flags);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1442,7 +1453,7 @@
     public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
-                mService.setMaximumTimeToLock(admin, timeMs, UserHandle.myUserId());
+                mService.setMaximumTimeToLock(admin, timeMs);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1507,8 +1518,8 @@
     public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
 
     /**
-     * Ask the user data be wiped.  This will cause the device to reboot,
-     * erasing all user data while next booting up.
+     * Ask the user data be wiped.  Wiping the primary user will cause the
+     * device to reboot, erasing all user data while next booting up.
      *
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
@@ -1592,7 +1603,7 @@
                             != android.net.Proxy.PROXY_VALID)
                         throw new IllegalArgumentException();
                 }
-                return mService.setGlobalProxy(admin, hostSpec, exclSpec, UserHandle.myUserId());
+                return mService.setGlobalProxy(admin, hostSpec, exclSpec);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1758,7 +1769,7 @@
     public int setStorageEncryption(ComponentName admin, boolean encrypt) {
         if (mService != null) {
             try {
-                return mService.setStorageEncryption(admin, encrypt, UserHandle.myUserId());
+                return mService.setStorageEncryption(admin, encrypt);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1977,7 +1988,7 @@
     public void setCameraDisabled(ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setCameraDisabled(admin, disabled, UserHandle.myUserId());
+                mService.setCameraDisabled(admin, disabled);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2021,7 +2032,7 @@
     public void setScreenCaptureDisabled(ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setScreenCaptureDisabled(admin, UserHandle.myUserId(), disabled);
+                mService.setScreenCaptureDisabled(admin, disabled);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2065,7 +2076,7 @@
     public void setAutoTimeRequired(ComponentName admin, boolean required) {
         if (mService != null) {
             try {
-                mService.setAutoTimeRequired(admin, UserHandle.myUserId(), required);
+                mService.setAutoTimeRequired(admin, required);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2106,7 +2117,7 @@
     public void setKeyguardDisabledFeatures(ComponentName admin, int which) {
         if (mService != null) {
             try {
-                mService.setKeyguardDisabledFeatures(admin, which, UserHandle.myUserId());
+                mService.setKeyguardDisabledFeatures(admin, which);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2688,8 +2699,7 @@
             PersistableBundle configuration) {
         if (mService != null) {
             try {
-                mService.setTrustAgentConfiguration(admin, target, configuration,
-                        UserHandle.myUserId());
+                mService.setTrustAgentConfiguration(admin, target, configuration);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2918,9 +2928,9 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageNames List of input method package names.
-     * @return true if setting the restriction succeeded. It will fail if there is
-     *     one or more input method enabled, that are not in the list or user if the foreground
-     *     user.
+     * @return true if setting the restriction succeeded. It will fail if there are
+     *     one or more non-system input methods currently enabled that are not in
+     *     the packageNames list.
      */
     public boolean setPermittedInputMethods(ComponentName admin, List<String> packageNames) {
         if (mService != null) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0ca60c0..67bca4e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -32,34 +32,34 @@
  * {@hide}
  */
 interface IDevicePolicyManager {
-    void setPasswordQuality(in ComponentName who, int quality, int userHandle);
+    void setPasswordQuality(in ComponentName who, int quality);
     int getPasswordQuality(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLength(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumLength(in ComponentName who, int length);
     int getPasswordMinimumLength(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumUpperCase(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumUpperCase(in ComponentName who, int length);
     int getPasswordMinimumUpperCase(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLowerCase(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumLowerCase(in ComponentName who, int length);
     int getPasswordMinimumLowerCase(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLetters(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumLetters(in ComponentName who, int length);
     int getPasswordMinimumLetters(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumNumeric(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumNumeric(in ComponentName who, int length);
     int getPasswordMinimumNumeric(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumSymbols(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumSymbols(in ComponentName who, int length);
     int getPasswordMinimumSymbols(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumNonLetter(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumNonLetter(in ComponentName who, int length);
     int getPasswordMinimumNonLetter(in ComponentName who, int userHandle);
 
-    void setPasswordHistoryLength(in ComponentName who, int length, int userHandle);
+    void setPasswordHistoryLength(in ComponentName who, int length);
     int getPasswordHistoryLength(in ComponentName who, int userHandle);
 
-    void setPasswordExpirationTimeout(in ComponentName who, long expiration, int userHandle);
+    void setPasswordExpirationTimeout(in ComponentName who, long expiration);
     long getPasswordExpirationTimeout(in ComponentName who, int userHandle);
 
     long getPasswordExpiration(in ComponentName who, int userHandle);
@@ -68,33 +68,33 @@
     int getCurrentFailedPasswordAttempts(int userHandle);
     int getProfileWithMinimumFailedPasswordsForWipe(int userHandle);
 
-    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, int userHandle);
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
     int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle);
 
-    boolean resetPassword(String password, int flags, int userHandle);
+    boolean resetPassword(String password, int flags);
 
-    void setMaximumTimeToLock(in ComponentName who, long timeMs, int userHandle);
+    void setMaximumTimeToLock(in ComponentName who, long timeMs);
     long getMaximumTimeToLock(in ComponentName who, int userHandle);
 
     void lockNow();
 
     void wipeData(int flags, int userHandle);
 
-    ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList, int userHandle);
+    ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
     ComponentName getGlobalProxyAdmin(int userHandle);
     void setRecommendedGlobalProxy(in ComponentName admin, in ProxyInfo proxyInfo);
 
-    int setStorageEncryption(in ComponentName who, boolean encrypt, int userHandle);
+    int setStorageEncryption(in ComponentName who, boolean encrypt);
     boolean getStorageEncryption(in ComponentName who, int userHandle);
     int getStorageEncryptionStatus(int userHandle);
 
-    void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle);
+    void setCameraDisabled(in ComponentName who, boolean disabled);
     boolean getCameraDisabled(in ComponentName who, int userHandle);
 
-    void setScreenCaptureDisabled(in ComponentName who, int userHandle, boolean disabled);
+    void setScreenCaptureDisabled(in ComponentName who, boolean disabled);
     boolean getScreenCaptureDisabled(in ComponentName who, int userHandle);
 
-    void setKeyguardDisabledFeatures(in ComponentName who, int which, int userHandle);
+    void setKeyguardDisabledFeatures(in ComponentName who, int which);
     int getKeyguardDisabledFeatures(in ComponentName who, int userHandle);
 
     void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle);
@@ -186,7 +186,7 @@
     boolean getCrossProfileCallerIdDisabledForUser(int userId);
 
     void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent,
-            in PersistableBundle args, int userId);
+            in PersistableBundle args);
     List<PersistableBundle> getTrustAgentConfiguration(in ComponentName admin,
             in ComponentName agent, int userId);
 
@@ -194,7 +194,7 @@
     boolean removeCrossProfileWidgetProvider(in ComponentName admin, String packageName);
     List<String> getCrossProfileWidgetProviders(in ComponentName admin);
 
-    void setAutoTimeRequired(in ComponentName who, int userHandle, boolean required);
+    void setAutoTimeRequired(in ComponentName who, boolean required);
     boolean getAutoTimeRequired();
 
     boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 0450150..767f59e 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.media.AudioManager;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -415,9 +416,16 @@
     }
 
     /**
-     * Tells remote device to adjust volume. Only if absolute volume is supported.
+     * Tells remote device to adjust volume. Only if absolute volume is
+     * supported. Uses the following values:
+     * <ul>
+     * <li>{@link AudioManager#ADJUST_LOWER}</li>
+     * <li>{@link AudioManager#ADJUST_RAISE}</li>
+     * <li>{@link AudioManager#ADJUST_MUTE}</li>
+     * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
+     * </ul>
      *
-     * @param direction 1 to increase volume, or -1 to decrease volume
+     * @param direction One of the supported adjust values.
      * @hide
      */
     public void adjustAvrcpAbsoluteVolume(int direction) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c262bae..b8f4bf8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1429,14 +1429,16 @@
                 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
                 synchronized (mManagerCallback) {
                     mService = bluetoothService;
-                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
-                        try {
-                            if (cb != null) {
-                                cb.onBluetoothServiceUp(bluetoothService);
-                            } else {
-                                Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
-                            }
-                        } catch (Exception e)  { Log.e(TAG,"",e);}
+                    synchronized (mProxyServiceStateCallbacks) {
+                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
+                            try {
+                                if (cb != null) {
+                                    cb.onBluetoothServiceUp(bluetoothService);
+                                } else {
+                                    Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
+                                }
+                            } catch (Exception e)  { Log.e(TAG,"",e);}
+                        }
                     }
                 }
             }
@@ -1448,14 +1450,16 @@
                     if (mLeScanClients != null) mLeScanClients.clear();
                     if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
                     if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
-                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
-                        try {
-                            if (cb != null) {
-                                cb.onBluetoothServiceDown();
-                            } else {
-                                Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
-                            }
-                        } catch (Exception e)  { Log.e(TAG,"",e);}
+                    synchronized (mProxyServiceStateCallbacks) {
+                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
+                            try {
+                                if (cb != null) {
+                                    cb.onBluetoothServiceDown();
+                                } else {
+                                    Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
+                                }
+                            } catch (Exception e)  { Log.e(TAG,"",e);}
+                        }
                     }
                 }
             }
@@ -1596,10 +1600,10 @@
             return mManagerService;
     }
 
-    private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
+    final private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
 
     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
-        synchronized (mManagerCallback) {
+        synchronized (mProxyServiceStateCallbacks) {
             if (cb == null) {
                 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
             } else if (!mProxyServiceStateCallbacks.contains(cb)) {
@@ -1610,7 +1614,7 @@
     }
 
     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
-        synchronized (mManagerCallback) {
+        synchronized (mProxyServiceStateCallbacks) {
             mProxyServiceStateCallbacks.remove(cb);
         }
     }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 5e50b69..bb0d0a3 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -67,6 +68,14 @@
     private static final boolean DBG = false;
 
     /**
+     * Connection state bitmask as returned by getConnectionState.
+     */
+    private static final int CONNECTION_STATE_DISCONNECTED = 0;
+    private static final int CONNECTION_STATE_CONNECTED = 1;
+    private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
+    private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
+
+    /**
      * Sentinel error value for this class. Guaranteed to not equal any other
      * integer constant in this class. Provided as a convenience for functions
      * that require a sentinel error value, for example:
@@ -940,13 +949,36 @@
      * @return True if there is at least one open connection to this device.
      * @hide
      */
+    @SystemApi
     public boolean isConnected() {
         if (sService == null) {
             // BT is not enabled, we cannot be connected.
             return false;
         }
         try {
-            return sService.isConnected(this);
+            return sService.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return false;
+        }
+    }
+
+    /**
+     * Returns whether there is an open connection to this device
+     * that has been encrypted.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+     *
+     * @return True if there is at least one encrypted connection to this device.
+     * @hide
+     */
+    @SystemApi
+    public boolean isEncrypted() {
+        if (sService == null) {
+            // BT is not enabled, we cannot be connected.
+            return false;
+        }
+        try {
+            return sService.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
             return false;
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index cd4535a..dabb1ce 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -59,7 +59,7 @@
     boolean cancelBondProcess(in BluetoothDevice device);
     boolean removeBond(in BluetoothDevice device);
     int getBondState(in BluetoothDevice device);
-    boolean isConnected(in BluetoothDevice device);
+    int getConnectionState(in BluetoothDevice device);
 
     String getRemoteName(in BluetoothDevice device);
     int getRemoteType(in BluetoothDevice device);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 37a46be..582802b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1760,6 +1760,7 @@
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     /**
@@ -3252,6 +3253,7 @@
     /**
      * @hide String array of package names.
      */
+    @SystemApi
     public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
 
     /**
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 46c9234..cd32dae 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import android.annotation.Nullable;
+
 import java.util.Map;
 import java.util.Set;
 
@@ -78,7 +80,7 @@
          * @return Returns a reference to the same Editor object, so you can
          * chain put calls together.
          */
-        Editor putString(String key, String value);
+        Editor putString(String key, @Nullable String value);
         
         /**
          * Set a set of String values in the preferences editor, to be written
@@ -91,7 +93,7 @@
          * @return Returns a reference to the same Editor object, so you can
          * chain put calls together.
          */
-        Editor putStringSet(String key, Set<String> values);
+        Editor putStringSet(String key, @Nullable Set<String> values);
         
         /**
          * Set an int value in the preferences editor, to be written back once
@@ -254,7 +256,8 @@
      * 
      * @throws ClassCastException
      */
-    String getString(String key, String defValue);
+    @Nullable
+    String getString(String key, @Nullable String defValue);
     
     /**
      * Retrieve a set of String values from the preferences.
@@ -272,7 +275,8 @@
      * 
      * @throws ClassCastException
      */
-    Set<String> getStringSet(String key, Set<String> defValues);
+    @Nullable
+    Set<String> getStringSet(String key, @Nullable Set<String> defValues);
     
     /**
      * Retrieve an int value from the preferences.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 641f843e..4723c0d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -641,6 +641,13 @@
      */
     public String parentActivityName;
 
+    /**
+     * Value indicating if the activity is resizeable to any dimension.
+     * See {@link android.R.attr#resizeableActivity}.
+     * @hide
+     */
+    public boolean resizeable;
+
     public ActivityInfo() {
     }
 
@@ -702,6 +709,7 @@
         if (uiOptions != 0) {
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
+        pw.println(prefix + "resizeable=" + resizeable);
         super.dumpBack(pw, prefix);
     }
     
@@ -730,6 +738,7 @@
         dest.writeString(parentActivityName);
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
+        dest.writeInt(resizeable ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -757,5 +766,6 @@
         parentActivityName = source.readString();
         persistableMode = source.readInt();
         maxRecents = source.readInt();
+        resizeable = (source.readInt() == 1);
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e07edba..e822708 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -334,44 +334,6 @@
     public static final int FLAG_FULL_BACKUP_ONLY = 1<<26;
 
     /**
-     * Value for {@link #flags}: true if the application is hidden via restrictions and for
-     * most purposes is considered as not installed.
-     * {@hide}
-     */
-    public static final int FLAG_HIDDEN = 1<<27;
-
-    /**
-     * Value for {@link #flags}: set to <code>true</code> if the application
-     * has reported that it is heavy-weight, and thus can not participate in
-     * the normal application lifecycle.
-     *
-     * <p>Comes from the
-     * android.R.styleable#AndroidManifestApplication_cantSaveState
-     * attribute of the &lt;application&gt; tag.
-     *
-     * {@hide}
-     */
-    public static final int FLAG_CANT_SAVE_STATE = 1<<28;
-
-    /**
-     * Value for {@link #flags}: Set to true if the application has been
-     * installed using the forward lock option.
-     *
-     * NOTE: DO NOT CHANGE THIS VALUE!  It is saved in packages.xml.
-     * 
-     * {@hide}
-     */
-    public static final int FLAG_FORWARD_LOCK = 1<<29;
-
-    /**
-     * Value for {@link #flags}: set to {@code true} if the application
-     * is permitted to hold privileged permissions.
-     *
-     * {@hide}
-     */
-    public static final int FLAG_PRIVILEGED = 1<<30;
-
-    /**
      * Value for {@link #flags}: true if code from this application will need to be
      * loaded into other applications' processes. On devices that support multiple
      * instruction sets, this implies the code might be loaded into a process that's
@@ -395,11 +357,60 @@
      * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
      * {@link #FLAG_RESIZEABLE_FOR_SCREENS},
      * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
-     * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}.
+     * {@link #FLAG_ALLOW_BACKUP}, {@link #FLAG_KILL_AFTER_RESTORE},
+     * {@link #FLAG_RESTORE_ANY_VERSION}, {@link #FLAG_EXTERNAL_STORAGE},
+     * {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
+     * {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
+     * {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
+     * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}.
      */
     public int flags = 0;
 
     /**
+     * Value for {@link #privateFlags}: true if the application is hidden via restrictions and for
+     * most purposes is considered as not installed.
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_HIDDEN = 1<<0;
+
+    /**
+     * Value for {@link #privateFlags}: set to <code>true</code> if the application
+     * has reported that it is heavy-weight, and thus can not participate in
+     * the normal application lifecycle.
+     *
+     * <p>Comes from the
+     * android.R.styleable#AndroidManifestApplication_cantSaveState
+     * attribute of the &lt;application&gt; tag.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1;
+
+    /**
+     * Value for {@link #privateFlags}: Set to true if the application has been
+     * installed using the forward lock option.
+     *
+     * NOTE: DO NOT CHANGE THIS VALUE!  It is saved in packages.xml.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2;
+
+    /**
+     * Value for {@link #privateFlags}: set to {@code true} if the application
+     * is permitted to hold privileged permissions.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
+
+    /**
+     * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
+     * {@hide}
+     */
+    public int privateFlags;
+
+    /**
      * The required smallest screen width the application can run on.  If 0,
      * nothing has been specified.  Comes from
      * {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
@@ -598,6 +609,7 @@
         pw.println(prefix + "processName=" + processName);
         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
@@ -680,6 +692,7 @@
         className = orig.className;
         theme = orig.theme;
         flags = orig.flags;
+        privateFlags = orig.privateFlags;
         requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
         compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
         largestWidthLimitDp = orig.largestWidthLimitDp;
@@ -730,6 +743,7 @@
         dest.writeString(className);
         dest.writeInt(theme);
         dest.writeInt(flags);
+        dest.writeInt(privateFlags);
         dest.writeInt(requiresSmallestWidthDp);
         dest.writeInt(compatibleWidthLimitDp);
         dest.writeInt(largestWidthLimitDp);
@@ -779,6 +793,7 @@
         className = source.readString();
         theme = source.readInt();
         flags = source.readInt();
+        privateFlags = source.readInt();
         requiresSmallestWidthDp = source.readInt();
         compatibleWidthLimitDp = source.readInt();
         largestWidthLimitDp = source.readInt();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0dc86ad..b518498 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@
 
     int getFlagsForUid(int uid);
 
+    int getPrivateFlagsForUid(int uid);
+
     boolean isUidPrivileged(int uid);
 
     String[] getAppOpPermissionPackages(String permissionName);
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index ee23fcd..87b97aa 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -39,6 +39,7 @@
 
     private ActivityInfo mActivityInfo;
     private ComponentName mComponentName;
+    private ResolveInfo mResolveInfo;
     private UserHandle mUser;
     private long mFirstInstallTime;
 
@@ -52,6 +53,7 @@
     LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user,
             long firstInstallTime) {
         this(context);
+        mResolveInfo = info;
         mActivityInfo = info.activityInfo;
         mComponentName = LauncherApps.getComponentName(info);
         mUser = user;
@@ -92,7 +94,7 @@
      * @return The label for the activity.
      */
     public CharSequence getLabel() {
-        return mActivityInfo.loadLabel(mPm);
+        return mResolveInfo.loadLabel(mPm);
     }
 
     /**
@@ -104,8 +106,22 @@
      * @return The drawable associated with the activity
      */
     public Drawable getIcon(int density) {
-        // TODO: Use density
-        return mActivityInfo.loadIcon(mPm);
+        int iconRes = mResolveInfo.getIconResource();
+        Resources resources = null;
+        Drawable icon = null;
+        // Get the preferred density icon from the app's resources
+        if (density != 0 && iconRes != 0) {
+            try {
+                resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+                icon = resources.getDrawableForDensity(iconRes, density);
+            } catch (NameNotFoundException | Resources.NotFoundException exc) {
+            }
+        }
+        // Get the default density icon
+        if (icon == null) {
+            icon = mResolveInfo.loadIcon(mPm);
+        }
+        return icon;
     }
 
     /**
@@ -151,23 +167,7 @@
      * @return A badged icon for the activity.
      */
     public Drawable getBadgedIcon(int density) {
-        int iconRes = mActivityInfo.getIconResource();
-        Resources resources = null;
-        Drawable originalIcon = null;
-        try {
-            resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
-            try {
-                if (density != 0) {
-                    originalIcon = resources.getDrawableForDensity(iconRes, density);
-                }
-            } catch (Resources.NotFoundException e) {
-            }
-        } catch (NameNotFoundException nnfe) {
-        }
-
-        if (originalIcon == null) {
-            originalIcon = mActivityInfo.loadIcon(mPm);
-        }
+        Drawable originalIcon = getIcon(density);
 
         if (originalIcon instanceof BitmapDrawable) {
             return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d7d9e8b..b0e0300 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -49,6 +49,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 
+import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -799,6 +800,7 @@
                 pkg.splitCodePaths = lite.splitCodePaths;
                 pkg.splitRevisionCodes = lite.splitRevisionCodes;
                 pkg.splitFlags = new int[num];
+                pkg.splitPrivateFlags = new int[num];
 
                 for (int i = 0; i < num; i++) {
                     parseSplitApk(pkg, i, assets, flags);
@@ -1404,7 +1406,7 @@
 
         /* Set the global "forward lock" flag */
         if ((flags & PARSE_FORWARD_LOCK) != 0) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
         }
 
         /* Set the global "on SD card" flag */
@@ -2607,7 +2609,7 @@
                 if (sa.getBoolean(
                         com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
                         false)) {
-                    ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE;
+                    ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
 
                     // A heavy-weight application can not be in a custom process.
                     // We can do direct compare because we intern all strings.
@@ -2759,9 +2761,17 @@
             }
         }
 
+        addSharedLibrariesForBackwardCompatibility(owner);
+
         return true;
     }
 
+    private static void addSharedLibrariesForBackwardCompatibility(Package owner) {
+        if (owner.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+            owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, "org.apache.http.legacy");
+        }
+    }
+
     /**
      * Parse the {@code application} XML tree at the current parse location in a
      * <em>split APK</em> manifest.
@@ -2946,20 +2956,19 @@
             XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
             boolean receiver, boolean hardwareAccelerated)
             throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(attrs,
-                com.android.internal.R.styleable.AndroidManifestActivity);
+        TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity);
 
         if (mParseActivityArgs == null) {
             mParseActivityArgs = new ParseComponentArgs(owner, outError,
-                    com.android.internal.R.styleable.AndroidManifestActivity_name,
-                    com.android.internal.R.styleable.AndroidManifestActivity_label,
-                    com.android.internal.R.styleable.AndroidManifestActivity_icon,
-                    com.android.internal.R.styleable.AndroidManifestActivity_logo,
-                    com.android.internal.R.styleable.AndroidManifestActivity_banner,
+                    R.styleable.AndroidManifestActivity_name,
+                    R.styleable.AndroidManifestActivity_label,
+                    R.styleable.AndroidManifestActivity_icon,
+                    R.styleable.AndroidManifestActivity_logo,
+                    R.styleable.AndroidManifestActivity_banner,
                     mSeparateProcesses,
-                    com.android.internal.R.styleable.AndroidManifestActivity_process,
-                    com.android.internal.R.styleable.AndroidManifestActivity_description,
-                    com.android.internal.R.styleable.AndroidManifestActivity_enabled);
+                    R.styleable.AndroidManifestActivity_process,
+                    R.styleable.AndroidManifestActivity_description,
+                    R.styleable.AndroidManifestActivity_enabled);
         }
         
         mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
@@ -2972,22 +2981,18 @@
             return null;
         }
 
-        boolean setExported = sa.hasValue(
-                com.android.internal.R.styleable.AndroidManifestActivity_exported);
+        boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
         if (setExported) {
-            a.info.exported = sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
+            a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
         }
 
-        a.info.theme = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
+        a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
 
-        a.info.uiOptions = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
+        a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
                 a.info.applicationInfo.uiOptions);
 
         String parentName = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName,
+                R.styleable.AndroidManifestActivity_parentActivityName,
                 Configuration.NATIVE_CONFIG_VERSION);
         if (parentName != null) {
             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
@@ -3001,8 +3006,7 @@
         }
 
         String str;
-        str = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
+        str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
         if (str == null) {
             a.info.permission = owner.applicationInfo.permission;
         } else {
@@ -3010,140 +3014,116 @@
         }
 
         str = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
+                R.styleable.AndroidManifestActivity_taskAffinity,
                 Configuration.NATIVE_CONFIG_VERSION);
         a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
                 owner.applicationInfo.taskAffinity, str, outError);
 
         a.info.flags = 0;
         if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
-                false)) {
+                R.styleable.AndroidManifestActivity_multiprocess, false)) {
             a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
             a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
             a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
             a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
             a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
             a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
                 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
             a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)) {
             a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_immersive,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
         }
 
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_primaryUserOnly, false)) {
+            a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
+        }
+
         if (!receiver) {
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
                     hardwareAccelerated)) {
                 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
             }
 
             a.info.launchMode = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
-                    ActivityInfo.LAUNCH_MULTIPLE);
+                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
             a.info.documentLaunchMode = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
+                    R.styleable.AndroidManifestActivity_documentLaunchMode,
                     ActivityInfo.DOCUMENT_LAUNCH_NONE);
             a.info.maxRecents = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_maxRecents,
+                    R.styleable.AndroidManifestActivity_maxRecents,
                     ActivityManager.getDefaultAppRecentsLimitStatic());
-            a.info.screenOrientation = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
-                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-            a.info.configChanges = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
-                    0);
+            a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
             a.info.softInputMode = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
-                    0);
+                    R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
 
             a.info.persistableMode = sa.getInteger(
-                    com.android.internal.R.styleable.AndroidManifestActivity_persistableMode,
+                    R.styleable.AndroidManifestActivity_persistableMode,
                     ActivityInfo.PERSIST_ROOT_ONLY);
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
                 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
             }
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
                 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
             }
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
                 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
             }
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_resumeWhilePausing,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
             }
+
+            a.info.resizeable = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_resizeableActivity,
+                    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.MNC);
+            if (a.info.resizeable) {
+                // Fixed screen orientation isn't supported with resizeable activities.
+                a.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+            } else {
+                a.info.screenOrientation = sa.getInt(
+                        R.styleable.AndroidManifestActivity_screenOrientation,
+                        ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+            }
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
-        }
 
-        if (receiver) {
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
                 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
                 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
                     Slog.w(TAG, "Activity exported request ignored due to singleUser: "
@@ -3153,16 +3133,12 @@
                     setExported = true;
                 }
             }
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly,
-                    false)) {
-                a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
-            }
         }
 
         sa.recycle();
 
-        if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+        if (receiver && (owner.applicationInfo.privateFlags
+                &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
             // A heavy-weight application can not have receives in its main process
             // We can do direct compare because we intern all strings.
             if (a.info.processName == owner.packageName) {
@@ -3515,7 +3491,8 @@
 
         sa.recycle();
 
-        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                != 0) {
             // A heavy-weight application can not have providers in its main process
             // We can do direct compare because we intern all strings.
             if (p.info.processName == owner.packageName) {
@@ -3794,7 +3771,8 @@
 
         sa.recycle();
 
-        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                != 0) {
             // A heavy-weight application can not have services in its main process
             // We can do direct compare because we intern all strings.
             if (s.info.processName == owner.packageName) {
@@ -4212,6 +4190,13 @@
         /** Flags of any split APKs; ordered by parsed splitName */
         public int[] splitFlags;
 
+        /**
+         * Private flags of any split APKs; ordered by parsed splitName.
+         *
+         * {@hide}
+         */
+        public int[] splitPrivateFlags;
+
         public boolean baseHardwareAccelerated;
 
         // For now we only support one application per package.
@@ -4647,9 +4632,9 @@
             ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
         if (state.hidden) {
-            ai.flags |= ApplicationInfo.FLAG_HIDDEN;
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
         } else {
-            ai.flags &= ~ApplicationInfo.FLAG_HIDDEN;
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
         }
         if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 4a743a5..a386097 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -35,6 +35,8 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -55,6 +57,8 @@
 import java.util.List;
 import java.util.Map;
 
+import libcore.io.IoUtils;
+
 /**
  * Cache of registered services. This cache is lazily built by interrogating
  * {@link PackageManager} on a per-user basis. It's updated as packages are
@@ -112,13 +116,19 @@
 
     public RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
             String attributeName, XmlSerializerAndParser<V> serializerAndParser) {
+        this(context, interfaceName, metaDataName, attributeName, serializerAndParser,
+                Environment.getDataDirectory());
+    }
+
+    @VisibleForTesting
+    protected RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
+            String attributeName, XmlSerializerAndParser<V> serializerAndParser, File dataDir) {
         mContext = context;
         mInterfaceName = interfaceName;
         mMetaDataName = metaDataName;
         mAttributesName = attributeName;
         mSerializerAndParser = serializerAndParser;
 
-        File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
         File syncDir = new File(systemDir, "registered_services");
         mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml"));
@@ -155,9 +165,19 @@
             // package is going away, but it's the middle of an upgrade: keep the current
             // state and do nothing here.  This clause is intentionally empty.
         } else {
+            int[] uids = null;
             // either we're adding/changing, or it's a removal without replacement, so
-            // we need to recalculate the set of available services
-            generateServicesMap(userId);
+            // we need to update the set of available services
+            if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)
+                    || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+                uids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+            } else {
+                int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                if (uid > 0) {
+                    uids = new int[] { uid };
+                }
+            }
+            generateServicesMap(uids, userId);
         }
     }
 
@@ -270,7 +290,7 @@
             // Find user and lazily populate cache
             final UserServices<V> user = findOrCreateUserLocked(userId);
             if (user.services == null) {
-                generateServicesMap(userId);
+                generateServicesMap(null, userId);
             }
             return user.services.get(type);
         }
@@ -285,14 +305,15 @@
             // Find user and lazily populate cache
             final UserServices<V> user = findOrCreateUserLocked(userId);
             if (user.services == null) {
-                generateServicesMap(userId);
+                generateServicesMap(null, userId);
             }
             return Collections.unmodifiableCollection(
                     new ArrayList<ServiceInfo<V>>(user.services.values()));
         }
     }
 
-    private boolean inSystemImage(int callerUid) {
+    @VisibleForTesting
+    protected boolean inSystemImage(int callerUid) {
         String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
         for (String name : packages) {
             try {
@@ -308,19 +329,27 @@
         return false;
     }
 
+    @VisibleForTesting
+    protected List<ResolveInfo> queryIntentServices(int userId) {
+        final PackageManager pm = mContext.getPackageManager();
+        return pm.queryIntentServicesAsUser(
+                new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
+    }
+
     /**
      * Populate {@link UserServices#services} by scanning installed packages for
      * given {@link UserHandle}.
+     * @param changedUids the array of uids that have been affected, as mentioned in the broadcast
+     *                    or null to assume that everything is affected.
+     * @param userId the user for whom to update the services map.
      */
-    private void generateServicesMap(int userId) {
+    private void generateServicesMap(int[] changedUids, int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "generateServicesMap() for " + userId);
+            Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids);
         }
 
-        final PackageManager pm = mContext.getPackageManager();
         final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
-        final List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(
-                new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
+        final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
         for (ResolveInfo resolveInfo : resolveInfos) {
             try {
                 ServiceInfo<V> info = parseServiceInfo(resolveInfo);
@@ -329,9 +358,7 @@
                     continue;
                 }
                 serviceInfos.add(info);
-            } catch (XmlPullParserException e) {
-                Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
-            } catch (IOException e) {
+            } catch (XmlPullParserException|IOException e) {
                 Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
             }
         }
@@ -341,8 +368,6 @@
             final boolean firstScan = user.services == null;
             if (firstScan) {
                 user.services = Maps.newHashMap();
-            } else {
-                user.services.clear();
             }
 
             StringBuilder changes = new StringBuilder();
@@ -399,7 +424,10 @@
 
             ArrayList<V> toBeRemoved = Lists.newArrayList();
             for (V v1 : user.persistentServices.keySet()) {
-                if (!containsType(serviceInfos, v1)) {
+                // Remove a persisted service that's not in the currently available services list.
+                // And only if it is in the list of changedUids.
+                if (!containsType(serviceInfos, v1)
+                        && containsUid(changedUids, user.persistentServices.get(v1))) {
                     toBeRemoved.add(v1);
                 }
             }
@@ -409,9 +437,20 @@
                 }
                 changed = true;
                 user.persistentServices.remove(v1);
+                user.services.remove(v1);
                 notifyListener(v1, userId, true /* removed */);
             }
             if (DEBUG) {
+                Log.d(TAG, "user.services=");
+                for (V v : user.services.keySet()) {
+                    Log.d(TAG, "  " + v + " " + user.services.get(v));
+                }
+                Log.d(TAG, "user.persistentServices=");
+                for (V v : user.persistentServices.keySet()) {
+                    Log.d(TAG, "  " + v + " " + user.persistentServices.get(v));
+                }
+            }
+            if (DEBUG) {
                 if (changes.length() > 0) {
                     Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
                             serviceInfos.size() + " services:\n" + changes);
@@ -426,6 +465,14 @@
         }
     }
 
+    /**
+     * Returns true if the list of changed uids is null (wildcard) or the specified uid
+     * is contained in the list of changed uids.
+     */
+    private boolean containsUid(int[] changedUids, int uid) {
+        return changedUids == null || ArrayUtils.contains(changedUids, uid);
+    }
+
     private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) {
         for (int i = 0, N = serviceInfos.size(); i < N; i++) {
             if (serviceInfos.get(i).type.equals(type)) {
@@ -447,7 +494,8 @@
         return false;
     }
 
-    private ServiceInfo<V> parseServiceInfo(ResolveInfo service)
+    @VisibleForTesting
+    protected ServiceInfo<V> parseServiceInfo(ResolveInfo service)
             throws XmlPullParserException, IOException {
         android.content.pm.ServiceInfo si = service.serviceInfo;
         ComponentName componentName = new ComponentName(si.packageName, si.name);
@@ -537,12 +585,7 @@
         } catch (Exception e) {
             Log.w(TAG, "Error reading persistent services, starting from scratch", e);
         } finally {
-            if (fis != null) {
-                try {
-                    fis.close();
-                } catch (java.io.IOException e1) {
-                }
-            }
+            IoUtils.closeQuietly(fis);
         }
     }
 
@@ -573,7 +616,7 @@
             out.endTag(null, "services");
             out.endDocument();
             mPersistentServicesFile.finishWrite(fos);
-        } catch (java.io.IOException e1) {
+        } catch (IOException e1) {
             Log.w(TAG, "Error writing accounts", e1);
             if (fos != null) {
                 mPersistentServicesFile.failWrite(fos);
@@ -581,6 +624,11 @@
         }
     }
 
+    @VisibleForTesting
+    protected Map<V, Integer> getPersistentServices(int userId) {
+        return findOrCreateUserLocked(userId).persistentServices;
+    }
+
     public abstract V parseServiceAttributes(Resources res,
             String packageName, AttributeSet attrs);
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index cf6a779..39f4cca 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -18,6 +18,7 @@
 package android.hardware;
 
 import android.os.Build;
+import android.annotation.SystemApi;
 
 /**
  * Class representing a sensor. Use {@link SensorManager#getSensorList} to get
@@ -511,6 +512,27 @@
      */
     public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
 
+     /**
+     * A constant describing a wrist tilt gesture sensor.
+     *
+     * A sensor of this type triggers when the device face is tilted towards the user.
+     * The only allowed return value is 1.0.
+     * This sensor remains active until disabled.
+     *
+     * @hide This sensor is expected to only be used by the system ui
+     */
+    @SystemApi
+    public static final int TYPE_WRIST_TILT_GESTURE = 26;
+
+    /**
+     * A constant string describing a wrist tilt gesture sensor.
+     *
+     * @hide This sensor is expected to only be used by the system ui
+     * @see #TYPE_WRIST_TILT_GESTURE
+     */
+    @SystemApi
+    public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
+
     /**
      * A constant describing all sensor types.
      */
@@ -591,6 +613,7 @@
             1, // SENSOR_TYPE_WAKE_GESTURE
             1, // SENSOR_TYPE_GLANCE_GESTURE
             1, // SENSOR_TYPE_PICK_UP_GESTURE
+            1, // SENSOR_TYPE_WRIST_TILT_GESTURE
     };
 
     /**
@@ -810,4 +833,96 @@
                 + ", type=" + mType + ", maxRange=" + mMaxRange + ", resolution=" + mResolution
                 + ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
     }
+
+    /**
+     * Sets the Type associated with the sensor.
+     * NOTE: to be used only by native bindings in SensorManager.
+     *
+     * This allows interned static strings to be used across all representations of the Sensor. If
+     * a sensor type is not referenced here, it will still be interned by the native SensorManager.
+     *
+     * @return {@code true} if the StringType was successfully set, {@code false} otherwise.
+     */
+    private boolean setType(int value) {
+        mType = value;
+        switch (mType) {
+            case TYPE_ACCELEROMETER:
+                mStringType = STRING_TYPE_ACCELEROMETER;
+                return true;
+            case TYPE_AMBIENT_TEMPERATURE:
+                mStringType = STRING_TYPE_AMBIENT_TEMPERATURE;
+                return true;
+            case TYPE_GAME_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_GAME_ROTATION_VECTOR;
+                return true;
+            case TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+                return true;
+            case TYPE_GLANCE_GESTURE:
+                mStringType = STRING_TYPE_GLANCE_GESTURE;
+                return true;
+            case TYPE_GRAVITY:
+                mStringType = STRING_TYPE_GRAVITY;
+                return true;
+            case TYPE_GYROSCOPE:
+                mStringType = STRING_TYPE_GYROSCOPE;
+                return true;
+            case TYPE_GYROSCOPE_UNCALIBRATED:
+                mStringType = STRING_TYPE_GYROSCOPE_UNCALIBRATED;
+                return true;
+            case TYPE_HEART_RATE:
+                mStringType = STRING_TYPE_HEART_RATE;
+                return true;
+            case TYPE_LIGHT:
+                mStringType = STRING_TYPE_LIGHT;
+                return true;
+            case TYPE_LINEAR_ACCELERATION:
+                mStringType = STRING_TYPE_LINEAR_ACCELERATION;
+                return true;
+            case TYPE_MAGNETIC_FIELD:
+                mStringType = STRING_TYPE_MAGNETIC_FIELD;
+                return true;
+            case TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+                mStringType = STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
+                return true;
+            case TYPE_PICK_UP_GESTURE:
+                mStringType = STRING_TYPE_PICK_UP_GESTURE;
+                return true;
+            case TYPE_PRESSURE:
+                mStringType = STRING_TYPE_PRESSURE;
+                return true;
+            case TYPE_PROXIMITY:
+                mStringType = STRING_TYPE_PROXIMITY;
+                return true;
+            case TYPE_RELATIVE_HUMIDITY:
+                mStringType = STRING_TYPE_RELATIVE_HUMIDITY;
+                return true;
+            case TYPE_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_ROTATION_VECTOR;
+                return true;
+            case TYPE_SIGNIFICANT_MOTION:
+                mStringType = STRING_TYPE_SIGNIFICANT_MOTION;
+                return true;
+            case TYPE_STEP_COUNTER:
+                mStringType = STRING_TYPE_STEP_COUNTER;
+                return true;
+            case TYPE_STEP_DETECTOR:
+                mStringType = STRING_TYPE_STEP_DETECTOR;
+                return true;
+            case TYPE_TILT_DETECTOR:
+                mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR;
+                return true;
+            case TYPE_WAKE_GESTURE:
+                mStringType = STRING_TYPE_WAKE_GESTURE;
+                return true;
+            case TYPE_ORIENTATION:
+                mStringType = STRING_TYPE_ORIENTATION;
+                return true;
+            case TYPE_TEMPERATURE:
+                mStringType = STRING_TYPE_TEMPERATURE;
+                return true;
+            default:
+                return false;
+        }
+    }
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index e4e5a8c..34b895b 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -451,7 +451,8 @@
         // non_wake-up version.
         if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
                 type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
-                type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE) {
+                type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
+                type == Sensor.TYPE_WRIST_TILT_GESTURE) {
             wakeUpSensor = true;
         }
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index eace1c4..60ff32c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -391,10 +391,12 @@
      * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation}, in counts of {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep},
      * that are supported by this camera device.</p>
      * <p><b>Range of valid values:</b><br></p>
+     * <p>Range [0,0] indicates that exposure compensation is not supported.</p>
+     * <p>For LIMITED and FULL devices, range must follow below requirements if exposure
+     * compensation is supported (<code>range != [0, 0]</code>):</p>
      * <p><code>Min.exposure compensation * {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} &lt;= -2 EV</code></p>
      * <p><code>Max.exposure compensation * {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} &gt;= 2 EV</code></p>
-     * <p>LEGACY devices may support a smaller range than this, including the range [0,0], which
-     * indicates that changing the exposure compensation is not supported.</p>
+     * <p>LEGACY devices may support a smaller range than this.</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
@@ -422,6 +424,17 @@
             new Key<Rational>("android.control.aeCompensationStep", Rational.class);
 
     /**
+     * <p>Whether the camera device supports {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock}</p>
+     * <p>LIMITED or FULL devices will always list <code>true</code></p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     */
+    @PublicKey
+    public static final Key<Boolean> CONTROL_AE_LOCK_AVAILABLE =
+            new Key<Boolean>("android.control.aeLockAvailable", boolean.class);
+
+    /**
      * <p>List of auto-focus (AF) modes for {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} that are
      * supported by this camera device.</p>
      * <p>Not all the auto-focus modes may be supported by a
@@ -469,6 +482,22 @@
             new Key<int[]>("android.control.availableEffects", int[].class);
 
     /**
+     * <p>List of control modes for {@link CaptureRequest#CONTROL_MODE android.control.mode} that are supported by this camera
+     * device.</p>
+     * <p>This list contains control modes that can be set for the camera device.
+     * LEGACY mode devices will always support AUTO mode. LIMITED and FULL
+     * devices will always support OFF, AUTO modes.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#CONTROL_MODE android.control.mode}</p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_MODE
+     */
+    @PublicKey
+    public static final Key<int[]> CONTROL_AVAILABLE_MODES =
+            new Key<int[]>("android.control.availableModes", int[].class);
+
+    /**
      * <p>List of scene modes for {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} that are supported by this camera
      * device.</p>
      * <p>This list contains scene modes that can be set for the camera device.
@@ -530,6 +559,17 @@
             new Key<int[]>("android.control.awbAvailableModes", int[].class);
 
     /**
+     * <p>Whether the camera device supports {@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}</p>
+     * <p>LIMITED or FULL devices will always list <code>true</code></p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AWB_LOCK
+     */
+    @PublicKey
+    public static final Key<Boolean> CONTROL_AWB_LOCK_AVAILABLE =
+            new Key<Boolean>("android.control.awbLockAvailable", boolean.class);
+
+    /**
      * <p>List of the maximum number of regions that can be used for metering in
      * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
      * this corresponds to the the maximum number of elements in
@@ -1069,8 +1109,11 @@
      * android.scaler.availableInputOutputFormatsMap. When using an
      * input stream, there must be at least one output stream
      * configured to to receive the reprocessed images.</p>
+     * <p>When an input stream and some output streams are used in a reprocessing request,
+     * only the input buffer will be used to produce these output stream buffers, and a
+     * new sensor image will not be captured.</p>
      * <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input
-     * stream image format will be RAW_OPAQUE, the associated output stream image format
+     * stream image format will be OPAQUE, the associated output stream image format
      * should be JPEG.</p>
      * <p><b>Range of valid values:</b><br></p>
      * <p>0 or 1.</p>
@@ -1080,8 +1123,8 @@
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     * @hide
      */
+    @PublicKey
     public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS =
             new Key<Integer>("android.request.maxNumInputStreams", int.class);
 
@@ -1157,8 +1200,10 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR MANUAL_SENSOR}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING MANUAL_POST_PROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING OPAQUE_REPROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -1167,8 +1212,10 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_RAW
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS
      * @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING
      */
     @PublicKey
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -1345,10 +1392,10 @@
      * <p>The mapping of image formats that are supported by this
      * camera device for input streams, to their corresponding output formats.</p>
      * <p>All camera devices with at least 1
-     * android.request.maxNumInputStreams will have at least one
+     * {@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} will have at least one
      * available input format.</p>
      * <p>The camera device will support the following map of formats,
-     * if its dependent capability is supported:</p>
+     * if its dependent capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}) is supported:</p>
      * <table>
      * <thead>
      * <tr>
@@ -1359,45 +1406,42 @@
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">OPAQUE</td>
      * <td align="left">JPEG</td>
-     * <td align="left">ZSL</td>
+     * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">OPAQUE</td>
      * <td align="left">YUV_420_888</td>
-     * <td align="left">ZSL</td>
+     * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">RAW_OPAQUE</td>
-     * <td align="left">RAW16</td>
-     * <td align="left">RAW</td>
-     * </tr>
-     * <tr>
-     * <td align="left">RAW16</td>
      * <td align="left">YUV_420_888</td>
-     * <td align="left">RAW</td>
-     * </tr>
-     * <tr>
-     * <td align="left">RAW16</td>
      * <td align="left">JPEG</td>
-     * <td align="left">RAW</td>
+     * <td align="left">YUV_REPROCESSING</td>
+     * </tr>
+     * <tr>
+     * <td align="left">YUV_420_888</td>
+     * <td align="left">YUV_420_888</td>
+     * <td align="left">YUV_REPROCESSING</td>
      * </tr>
      * </tbody>
      * </table>
-     * <p>For ZSL-capable camera devices, using the RAW_OPAQUE format
+     * <p>OPAQUE refers to a device-internal format that is not directly application-visible.
+     * An OPAQUE input or output surface can be acquired by
+     * OpaqueImageRingBufferQueue#getInputSurface() or
+     * OpaqueImageRingBufferQueue#getOutputSurface().
+     * For a OPAQUE_REPROCESSING-capable camera device, using the OPAQUE format
      * as either input or output will never hurt maximum frame rate (i.e.
-     * StreamConfigurationMap#getOutputStallDuration(int,Size)
-     * for a <code>format =</code> RAW_OPAQUE is always 0).</p>
+     * StreamConfigurationMap#getOutputStallDuration(klass,Size) is always 0),
+     * where klass is android.media.OpaqueImageRingBufferQueue.class.</p>
      * <p>Attempting to configure an input stream with output streams not
      * listed as available in this map is not valid.</p>
      * <p>TODO: typedef to ReprocessFormatMap</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     * <p><b>Full capability</b> -
-     * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
-     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
-     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @hide
      */
     public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
@@ -1899,6 +1943,23 @@
             new Key<Integer>("android.sensor.info.timestampSource", int.class);
 
     /**
+     * <p>Whether the RAW images output from this camera device are subject to
+     * lens shading correction.</p>
+     * <p>If TRUE, all images produced by the camera device in the RAW image formats will
+     * have lens shading correction already applied to it. If FALSE, the images will
+     * not be adjusted for lens shading correction.
+     * See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image formats.</p>
+     * <p>This key will be <code>null</code> for all devices do not report this information.
+     * Devices with RAW capability will always report this information in this key.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW
+     */
+    @PublicKey
+    public static final Key<Boolean> SENSOR_INFO_LENS_SHADING_APPLIED =
+            new Key<Boolean>("android.sensor.info.lensShadingApplied", boolean.class);
+
+    /**
      * <p>The standard reference illuminant used as the scene light source when
      * calculating the {@link CameraCharacteristics#SENSOR_COLOR_TRANSFORM1 android.sensor.colorTransform1},
      * {@link CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1 android.sensor.calibrationTransform1}, and
@@ -2189,6 +2250,22 @@
             new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
 
     /**
+     * <p>List of lens shading modes for {@link CaptureRequest#SHADING_MODE android.shading.mode} that are supported by this camera device.</p>
+     * <p>This list contains lens shading modes that can be set for the camera device.
+     * Camera devices that support the MANUAL_POST_PROCESSING capability will always
+     * list OFF and FAST mode. This includes all FULL level devices.
+     * LEGACY devices will always only support FAST mode.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#SHADING_MODE android.shading.mode}</p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#SHADING_MODE
+     */
+    @PublicKey
+    public static final Key<int[]> SHADING_AVAILABLE_MODES =
+            new Key<int[]>("android.shading.availableModes", int[].class);
+
+    /**
      * <p>List of face detection modes for {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} that are
      * supported by this camera device.</p>
      * <p>OFF is always supported.</p>
@@ -2232,6 +2309,23 @@
             new Key<boolean[]>("android.statistics.info.availableHotPixelMapModes", boolean[].class);
 
     /**
+     * <p>List of lens shading map output modes for {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} that
+     * are supported by this camera device.</p>
+     * <p>If no lens shading map output is available for this camera device, this key will
+     * contain only OFF.</p>
+     * <p>ON is always supported on devices with the RAW capability.
+     * LEGACY mode devices will always only support OFF.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode}</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+     */
+    @PublicKey
+    public static final Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES =
+            new Key<byte[]>("android.statistics.info.availableLensShadingMapModes", byte[].class);
+
+    /**
      * <p>Maximum number of supported points in the
      * tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.</p>
      * <p>If the actual number of points provided by the application (in {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}*) is
@@ -2255,8 +2349,13 @@
     /**
      * <p>List of tonemapping modes for {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} that are supported by this camera
      * device.</p>
-     * <p>Camera devices that support the MANUAL_POST_PROCESSING capability will always list
-     * CONTRAST_CURVE and FAST. This includes all FULL level devices.</p>
+     * <p>Camera devices that support the MANUAL_POST_PROCESSING capability will always contain
+     * at least one of below mode combinations:</p>
+     * <ul>
+     * <li>CONTRAST_CURVE and FAST</li>
+     * <li>GAMMA_VALUE, PRESET_CURVE, and FAST</li>
+     * </ul>
+     * <p>This includes all FULL level devices.</p>
      * <p><b>Range of valid values:</b><br>
      * Any value listed in {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index f6df302..ffe30d4 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -374,13 +374,19 @@
      * The camera device supports basic manual control of the image post-processing
      * stages. This means the following controls are guaranteed to be supported:</p>
      * <ul>
-     * <li>Manual tonemap control<ul>
+     * <li>
+     * <p>Manual tonemap control</p>
+     * <ul>
      * <li>{@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}</li>
      * <li>{@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</li>
      * <li>{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</li>
+     * <li>{@link CaptureRequest#TONEMAP_GAMMA android.tonemap.gamma}</li>
+     * <li>{@link CaptureRequest#TONEMAP_PRESET_CURVE android.tonemap.presetCurve}</li>
      * </ul>
      * </li>
-     * <li>Manual white balance control<ul>
+     * <li>
+     * <p>Manual white balance control</p>
+     * <ul>
      * <li>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}</li>
      * <li>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}</li>
      * </ul>
@@ -410,8 +416,10 @@
      * @see CaptureRequest#SHADING_MODE
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see CaptureRequest#TONEMAP_CURVE
+     * @see CaptureRequest#TONEMAP_GAMMA
      * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
      * @see CaptureRequest#TONEMAP_MODE
+     * @see CaptureRequest#TONEMAP_PRESET_CURVE
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2;
@@ -439,23 +447,40 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3;
 
     /**
-     * <p>The camera device supports the Zero Shutter Lag use case.</p>
+     * <p>The camera device supports the Zero Shutter Lag reprocessing use case.</p>
      * <ul>
-     * <li>At least one input stream can be used.</li>
-     * <li>RAW_OPAQUE is supported as an output/input format</li>
-     * <li>Using RAW_OPAQUE does not cause a frame rate drop
+     * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
+     * <li>OPAQUE is supported as an output/input format, that is,
+     *   StreamConfigurationMap#getOutputSizes(klass) and
+     *   StreamConfigurationMap#getInputSizes(klass) return non empty Size[] and have common
+     *   sizes, where klass is android.media.OpaqueImageRingBufferQueue.class. See
+     *   android.scaler.availableInputOutputFormatsMap for detailed information about
+     *   OPAQUE format.</li>
+     * <li>android.scaler.availableInputOutputFormatsMap has the required map entries.</li>
+     * <li>Using OPAQUE does not cause a frame rate drop
      *   relative to the sensor's maximum capture rate (at that
-     *   resolution).</li>
-     * <li>RAW_OPAQUE will be reprocessable into both YUV_420_888
+     *   resolution), see android.scaler.availableInputOutputFormatsMap for more details.</li>
+     * <li>OPAQUE will be reprocessable into both YUV_420_888
      *   and JPEG formats.</li>
-     * <li>The maximum available resolution for RAW_OPAQUE streams
+     * <li>The maximum available resolution for OPAQUE streams
      *   (both input/output) will match the maximum available
      *   resolution of JPEG streams.</li>
+     * <li>Only below controls are effective for reprocessing requests and
+     *   will be present in capture results, other controls in reprocess
+     *   requests will be ignored by the camera device.<ul>
+     * <li>android.jpeg.*</li>
+     * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
+     * <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
      * </ul>
+     * </li>
+     * </ul>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
-     * @hide
      */
-    public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4;
 
     /**
      * <p>The camera device supports accurately reporting the sensor settings for many of
@@ -515,6 +540,45 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6;
 
+    /**
+     * <p>The camera device supports the YUV420_888 reprocessing use case, similar as
+     * OPAQUE_REPROCESSING, This capability requires the camera device to support the
+     * following:</p>
+     * <ul>
+     * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
+     * <li>YUV420_888 is supported as a common format for both input and output, that is,
+     *   StreamConfigurationMap#getOutputSizes(YUV420_888) and
+     *   StreamConfigurationMap#getInputSizes(YUV420_888) return non empty Size[] and have
+     *   common sizes.</li>
+     * <li>android.scaler.availableInputOutputFormatsMap has the required map entries.</li>
+     * <li>Using YUV420_888 does not cause a frame rate drop
+     *   relative to the sensor's maximum capture rate (at that
+     *   resolution), see android.scaler.availableInputOutputFormatsMap for more details.</li>
+     * <li>YUV420_888 will be reprocessable into both YUV_420_888
+     *   and JPEG formats.</li>
+     * <li>The maximum available resolution for YUV420_888 streams
+     *   (both input/output) will match the maximum available
+     *   resolution of JPEG streams.</li>
+     * <li>Only the below controls are effective for reprocessing requests and will be
+     *   present in capture results. The reprocess requests are from the original capture
+     *   results that are assocaited with the intermidate YUV420_888 output buffers.
+     *   All other controls in the reprocess requests will be ignored by the camera device.<ul>
+     * <li>android.jpeg.*</li>
+     * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
+     * <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
+     * <li>{@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}</li>
+     * </ul>
+     * </li>
+     * </ul>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
@@ -973,6 +1037,14 @@
      */
     public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
 
+    /**
+     * <p>The camera device will cancel any currently active or completed
+     * precapture metering sequence, the auto-exposure routine will return to its
+     * initial state.</p>
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     */
+    public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2;
+
     //
     // Enumeration values for CaptureRequest#CONTROL_AF_MODE
     //
@@ -1830,6 +1902,13 @@
      */
     public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
 
+    /**
+     * <p>MINIMAL noise reduction is applied without reducing frame rate relative to
+     * sensor output. </p>
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     */
+    public static final int NOISE_REDUCTION_MODE_MINIMAL = 3;
+
     //
     // Enumeration values for CaptureRequest#SENSOR_TEST_PATTERN_MODE
     //
@@ -2033,6 +2112,47 @@
      */
     public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
 
+    /**
+     * <p>Use the gamma value specified in {@link CaptureRequest#TONEMAP_GAMMA android.tonemap.gamma} to peform
+     * tonemapping.</p>
+     * <p>All color enhancement and tonemapping must be disabled, except
+     * for applying the tonemapping curve specified by {@link CaptureRequest#TONEMAP_GAMMA android.tonemap.gamma}.</p>
+     * <p>Must not slow down frame rate relative to raw sensor output.</p>
+     *
+     * @see CaptureRequest#TONEMAP_GAMMA
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_GAMMA_VALUE = 3;
+
+    /**
+     * <p>Use the preset tonemapping curve specified in
+     * {@link CaptureRequest#TONEMAP_PRESET_CURVE android.tonemap.presetCurve} to peform tonemapping.</p>
+     * <p>All color enhancement and tonemapping must be disabled, except
+     * for applying the tonemapping curve specified by
+     * {@link CaptureRequest#TONEMAP_PRESET_CURVE android.tonemap.presetCurve}.</p>
+     * <p>Must not slow down frame rate relative to raw sensor output.</p>
+     *
+     * @see CaptureRequest#TONEMAP_PRESET_CURVE
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_PRESET_CURVE = 4;
+
+    //
+    // Enumeration values for CaptureRequest#TONEMAP_PRESET_CURVE
+    //
+
+    /**
+     * <p>Tonemapping curve is defined by sRGB</p>
+     * @see CaptureRequest#TONEMAP_PRESET_CURVE
+     */
+    public static final int TONEMAP_PRESET_CURVE_SRGB = 0;
+
+    /**
+     * <p>Tonemapping curve is defined by ITU-R BT.709</p>
+     * @see CaptureRequest#TONEMAP_PRESET_CURVE
+     */
+    public static final int TONEMAP_PRESET_CURVE_REC709 = 1;
+
     //
     // Enumeration values for CaptureResult#CONTROL_AE_STATE
     //
@@ -2080,7 +2200,10 @@
      * <p>AE has been asked to do a precapture sequence
      * and is currently executing it.</p>
      * <p>Precapture can be triggered through setting
-     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START.</p>
+     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START. Currently
+     * active and completed (if it causes camera device internal AE lock) precapture
+     * metering sequence can be canceled through setting
+     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to CANCEL.</p>
      * <p>Once PRECAPTURE completes, AE will transition to CONVERGED
      * or FLASH_REQUIRED as appropriate. This is a transient
      * state, the camera device may skip reporting this state in
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 0849df8..7569ea5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -552,6 +552,8 @@
      * in this matrix result metadata. The transform should keep the magnitude
      * of the output color values within <code>[0, 1.0]</code> (assuming input color
      * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
+     * <p>The valid range of each matrix element varies on different devices, but
+     * values within [-1.5, 3.0] are guaranteed not to be clipped.</p>
      * <p><b>Units</b>: Unitless scale factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -575,6 +577,10 @@
      * TRANSFORM_MATRIX.</p>
      * <p>The gains in the result metadata are the gains actually
      * applied by the camera device to the current frame.</p>
+     * <p>The valid range of gains varies on different devices, but gains
+     * between [1.0, 3.0] are guaranteed not to be clipped. Even if a given
+     * device allows gains below 1.0, this is usually not recommended because
+     * this can create color artifacts.</p>
      * <p><b>Units</b>: Unitless gain factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -724,7 +730,14 @@
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
      * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
      * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
-     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.
+     * Similarly, AE precapture trigger CANCEL has no effect when AE is already locked.</p>
+     * <p>When an AE precapture sequence is triggered, AE unlock will not be able to unlock
+     * the AE if AE is locked by the camera device internally during precapture metering
+     * sequence In other words, submitting requests with AE unlock has no effect for an
+     * ongoing precapture metering sequence. Otherwise, the precapture metering sequence
+     * will never succeed in a sequence of preview requests where AE lock is always set
+     * to <code>false</code>.</p>
      * <p>Since the camera device has a pipeline of in-flight requests, the settings that
      * get locked do not necessarily correspond to the settings that were present in the
      * latest capture result received from the camera device, since additional captures
@@ -867,9 +880,14 @@
      * metering sequence when it processes this request.</p>
      * <p>This entry is normally set to IDLE, or is not
      * included at all in the request settings. When included and
-     * set to START, the camera device will trigger the autoexposure
+     * set to START, the camera device will trigger the auto-exposure (AE)
      * precapture metering sequence.</p>
-     * <p>The precapture sequence should triggered before starting a
+     * <p>When set to CANCEL, the camera device will cancel any active
+     * precapture metering trigger, and return to its initial AE state.
+     * If a precapture metering sequence is already completed, and the camera
+     * device has implicitly locked the AE for subsequent still capture, the
+     * CANCEL trigger will unlock the AE and return to its initial AE state.</p>
+     * <p>The precapture sequence should be triggered before starting a
      * high-quality still capture for final metering decisions to
      * be made, and for firing pre-capture flash pulses to estimate
      * scene brightness and required final capture flash power, when
@@ -877,6 +895,18 @@
      * <p>Normally, this entry should be set to START for only a
      * single request, and the application should wait until the
      * sequence completes before starting a new one.</p>
+     * <p>When a precapture metering sequence is finished, the camera device
+     * may lock the auto-exposure routine internally to be able to accurately expose the
+     * subsequent still capture image (<code>{@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} == STILL_CAPTURE</code>).
+     * For this case, the AE may not resume normal scan if no subsequent still capture is
+     * submitted. To ensure that the AE routine restarts normal scan, the application should
+     * submit a request with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == true</code>, followed by a request
+     * with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == false</code>, if the application decides not to submit a
+     * still capture request after the precapture sequence completes. Alternatively, for
+     * API level 23 or newer devices, the CANCEL can be used to unlock the camera device
+     * internally locked AE if the application doesn't submit a still capture request after
+     * the AE precapture trigger. Note that, the CANCEL was added in API level 23, and must not
+     * be used in devices that have earlier API levels.</p>
      * <p>The exact effect of auto-exposure (AE) precapture trigger
      * depends on the current AE mode and state; see
      * {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
@@ -889,16 +919,20 @@
      * <ul>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_START START}</li>
+     *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL CANCEL}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
+     * @see CaptureRequest#CONTROL_AE_LOCK
      * @see CaptureResult#CONTROL_AE_STATE
+     * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
      */
     @PublicKey
     public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
@@ -1154,7 +1188,7 @@
      * <p>This control (except for MANUAL) is only effective if
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
      * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains OPAQUE_REPROCESSING. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * contains MANUAL_SENSOR. Other intent values are always supported.</p>
      * <p><b>Possible values:</b>
      * <ul>
@@ -1239,10 +1273,6 @@
      * update, as if this frame is never captured. This mode can be used in the scenario
      * where the application doesn't want a 3A manual control capture to affect
      * the subsequent auto 3A capture results.</p>
-     * <p>LEGACY mode devices will only support AUTO and USE_SCENE_MODE modes.
-     * LIMITED mode devices will only support OFF and OFF_KEEP_STATE if they
-     * support the MANUAL_SENSOR and MANUAL_POST_PROCSESING capabilities.
-     * FULL mode devices will always support OFF and OFF_KEEP_STATE.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #CONTROL_MODE_OFF OFF}</li>
@@ -1250,9 +1280,12 @@
      *   <li>{@link #CONTROL_MODE_USE_SCENE_MODE USE_SCENE_MODE}</li>
      *   <li>{@link #CONTROL_MODE_OFF_KEEP_STATE OFF_KEEP_STATE}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_MODES android.control.availableModes}</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_MODES
      * @see #CONTROL_MODE_OFF
      * @see #CONTROL_MODE_AUTO
      * @see #CONTROL_MODE_USE_SCENE_MODE
@@ -1372,6 +1405,10 @@
      * camera device will use the highest-quality enhancement algorithms,
      * even if it slows down capture rate. FAST means the camera device will
      * not slow down capture rate when applying edge enhancement.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera
+     * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
+     * The camera device may adjust its internal noise reduction parameters for best
+     * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #EDGE_MODE_OFF OFF}</li>
@@ -1387,6 +1424,7 @@
      *
      * @see CameraCharacteristics#EDGE_AVAILABLE_EDGE_MODES
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #EDGE_MODE_OFF
      * @see #EDGE_MODE_FAST
      * @see #EDGE_MODE_HIGH_QUALITY
@@ -1751,18 +1789,28 @@
     /**
      * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>The noise reduction algorithm attempts to improve image quality by removing
-     * excessive noise added by the capture process, especially in dark conditions.
-     * OFF means no noise reduction will be applied by the camera device.</p>
+     * excessive noise added by the capture process, especially in dark conditions.</p>
+     * <p>OFF means no noise reduction will be applied by the camera device, for both raw and
+     * YUV domain.</p>
+     * <p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,to remove
+     * demosaicing or other processing artifacts. For YUV_REPROCESSING, MINIMAL is same as OFF.
+     * This mode is optional, may not be support by all devices. The application should check
+     * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes} before using it.</p>
      * <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
      * will be applied. HIGH_QUALITY mode indicates that the camera device
      * will use the highest-quality noise filtering algorithms,
      * even if it slows down capture rate. FAST means the camera device will not
      * slow down capture rate when applying noise filtering.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera device
+     * will apply FAST/HIGH_QUALITY YUV domain noise reduction, respectively. The camera device
+     * may adjust the noise reduction parameters for best image quality based on the
+     * {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor} if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #NOISE_REDUCTION_MODE_OFF OFF}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_FAST FAST}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #NOISE_REDUCTION_MODE_MINIMAL MINIMAL}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}</p>
@@ -1773,9 +1821,11 @@
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #NOISE_REDUCTION_MODE_OFF
      * @see #NOISE_REDUCTION_MODE_FAST
      * @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
+     * @see #NOISE_REDUCTION_MODE_MINIMAL
      */
     @PublicKey
     public static final Key<Integer> NOISE_REDUCTION_MODE =
@@ -2068,6 +2118,8 @@
      *   <li>{@link #SHADING_MODE_FAST FAST}</li>
      *   <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2076,6 +2128,7 @@
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#SHADING_AVAILABLE_MODES
      * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see #SHADING_MODE_OFF
@@ -2138,12 +2191,15 @@
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
      */
@@ -2330,6 +2386,8 @@
      *   <li>{@link #TONEMAP_MODE_CONTRAST_CURVE CONTRAST_CURVE}</li>
      *   <li>{@link #TONEMAP_MODE_FAST FAST}</li>
      *   <li>{@link #TONEMAP_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #TONEMAP_MODE_GAMMA_VALUE GAMMA_VALUE}</li>
+     *   <li>{@link #TONEMAP_MODE_PRESET_CURVE PRESET_CURVE}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}</p>
@@ -2345,12 +2403,60 @@
      * @see #TONEMAP_MODE_CONTRAST_CURVE
      * @see #TONEMAP_MODE_FAST
      * @see #TONEMAP_MODE_HIGH_QUALITY
+     * @see #TONEMAP_MODE_GAMMA_VALUE
+     * @see #TONEMAP_MODE_PRESET_CURVE
      */
     @PublicKey
     public static final Key<Integer> TONEMAP_MODE =
             new Key<Integer>("android.tonemap.mode", int.class);
 
     /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * GAMMA_VALUE</p>
+     * <p>The tonemap curve will be defined the following formula:
+     * * OUT = pow(IN, 1.0 / gamma)
+     * where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
+     * pow is the power function and gamma is the gamma value specified by this
+     * key.</p>
+     * <p>The same curve will be applied to all color channels. The camera device
+     * may clip the input gamma value to its supported range. The actual applied
+     * value will be returned in capture result.</p>
+     * <p>The valid range of gamma value varies on different devices, but values
+     * within [1.0, 5.0] are guaranteed not to be clipped.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    @PublicKey
+    public static final Key<Float> TONEMAP_GAMMA =
+            new Key<Float>("android.tonemap.gamma", float.class);
+
+    /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * PRESET_CURVE</p>
+     * <p>The tonemap curve will be defined by specified standard.</p>
+     * <p>sRGB (approximated by 16 control points):</p>
+     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p>Rec. 709 (approximated by 16 control points):</p>
+     * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+     * <p>Note that above figures show a 16 control points approximation of preset
+     * curves. Camera devices may apply a different approximation to the curve.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_SRGB SRGB}</li>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_REC709 REC709}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     * @see #TONEMAP_PRESET_CURVE_SRGB
+     * @see #TONEMAP_PRESET_CURVE_REC709
+     */
+    @PublicKey
+    public static final Key<Integer> TONEMAP_PRESET_CURVE =
+            new Key<Integer>("android.tonemap.presetCurve", int.class);
+
+    /**
      * <p>This LED is nominally used to indicate to the user
      * that the camera is powered on and may be streaming images back to the
      * Application Processor. In certain rare circumstances, the OS may
@@ -2416,6 +2522,52 @@
     public static final Key<Boolean> BLACK_LEVEL_LOCK =
             new Key<Boolean>("android.blackLevel.lock", boolean.class);
 
+    /**
+     * <p>The amount of exposure time increase factor applied to the original output
+     * frame by the application processing before sending for reprocessing.</p>
+     * <p>This is optional, and will be supported if the camera device supports YUV_REPROCESSING
+     * capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains YUV_REPROCESSING).</p>
+     * <p>For some YUV reprocessing use cases, the application may choose to filter the original
+     * output frames to effectively reduce the noise to the same level as a frame that was
+     * captured with longer exposure time. To be more specific, assuming the original captured
+     * images were captured with a sensitivity of S and an exposure time of T, the model in
+     * the camera device is that the amount of noise in the image would be approximately what
+     * would be expected if the original capture parameters had been a sensitivity of
+     * S/effectiveExposureFactor and an exposure time of T*effectiveExposureFactor, rather
+     * than S and T respectively. If the captured images were processed by the application
+     * before being sent for reprocessing, then the application may have used image processing
+     * algorithms and/or multi-frame image fusion to reduce the noise in the
+     * application-processed images (input images). By using the effectiveExposureFactor
+     * control, the application can communicate to the camera device the actual noise level
+     * improvement in the application-processed image. With this information, the camera
+     * device can select appropriate noise reduction and edge enhancement parameters to avoid
+     * excessive noise reduction ({@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}) and insufficient edge
+     * enhancement ({@link CaptureRequest#EDGE_MODE android.edge.mode}) being applied to the reprocessed frames.</p>
+     * <p>For example, for multi-frame image fusion use case, the application may fuse
+     * multiple output frames together to a final frame for reprocessing. When N image are
+     * fused into 1 image for reprocessing, the exposure time increase factor could be up to
+     * square root of N (based on a simple photon shot noise model). The camera device will
+     * adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
+     * produce the best quality images.</p>
+     * <p>This is relative factor, 1.0 indicates the application hasn't processed the input
+     * buffer in a way that affects its effective exposure time.</p>
+     * <p>This control is only effective for YUV reprocessing capture request. For noise
+     * reduction reprocessing, it is only effective when <code>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} != OFF</code>.
+     * Similarly, for edge enhancement reprocessing, it is only effective when
+     * <code>{@link CaptureRequest#EDGE_MODE android.edge.mode} != OFF</code>.</p>
+     * <p><b>Units</b>: Relative exposure time increase factor.</p>
+     * <p><b>Range of valid values:</b><br>
+     * &gt;= 1.0</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    @PublicKey
+    public static final Key<Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR =
+            new Key<Float>("android.reprocess.effectiveExposureFactor", float.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 1396940..b84dc2e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -403,6 +403,8 @@
      * in this matrix result metadata. The transform should keep the magnitude
      * of the output color values within <code>[0, 1.0]</code> (assuming input color
      * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
+     * <p>The valid range of each matrix element varies on different devices, but
+     * values within [-1.5, 3.0] are guaranteed not to be clipped.</p>
      * <p><b>Units</b>: Unitless scale factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -426,6 +428,10 @@
      * TRANSFORM_MATRIX.</p>
      * <p>The gains in the result metadata are the gains actually
      * applied by the camera device to the current frame.</p>
+     * <p>The valid range of gains varies on different devices, but gains
+     * between [1.0, 3.0] are guaranteed not to be clipped. Even if a given
+     * device allows gains below 1.0, this is usually not recommended because
+     * this can create color artifacts.</p>
      * <p><b>Units</b>: Unitless gain factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -575,7 +581,14 @@
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
      * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
      * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
-     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.
+     * Similarly, AE precapture trigger CANCEL has no effect when AE is already locked.</p>
+     * <p>When an AE precapture sequence is triggered, AE unlock will not be able to unlock
+     * the AE if AE is locked by the camera device internally during precapture metering
+     * sequence In other words, submitting requests with AE unlock has no effect for an
+     * ongoing precapture metering sequence. Otherwise, the precapture metering sequence
+     * will never succeed in a sequence of preview requests where AE lock is always set
+     * to <code>false</code>.</p>
      * <p>Since the camera device has a pipeline of in-flight requests, the settings that
      * get locked do not necessarily correspond to the settings that were present in the
      * latest capture result received from the camera device, since additional captures
@@ -718,9 +731,14 @@
      * metering sequence when it processes this request.</p>
      * <p>This entry is normally set to IDLE, or is not
      * included at all in the request settings. When included and
-     * set to START, the camera device will trigger the autoexposure
+     * set to START, the camera device will trigger the auto-exposure (AE)
      * precapture metering sequence.</p>
-     * <p>The precapture sequence should triggered before starting a
+     * <p>When set to CANCEL, the camera device will cancel any active
+     * precapture metering trigger, and return to its initial AE state.
+     * If a precapture metering sequence is already completed, and the camera
+     * device has implicitly locked the AE for subsequent still capture, the
+     * CANCEL trigger will unlock the AE and return to its initial AE state.</p>
+     * <p>The precapture sequence should be triggered before starting a
      * high-quality still capture for final metering decisions to
      * be made, and for firing pre-capture flash pulses to estimate
      * scene brightness and required final capture flash power, when
@@ -728,6 +746,18 @@
      * <p>Normally, this entry should be set to START for only a
      * single request, and the application should wait until the
      * sequence completes before starting a new one.</p>
+     * <p>When a precapture metering sequence is finished, the camera device
+     * may lock the auto-exposure routine internally to be able to accurately expose the
+     * subsequent still capture image (<code>{@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} == STILL_CAPTURE</code>).
+     * For this case, the AE may not resume normal scan if no subsequent still capture is
+     * submitted. To ensure that the AE routine restarts normal scan, the application should
+     * submit a request with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == true</code>, followed by a request
+     * with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == false</code>, if the application decides not to submit a
+     * still capture request after the precapture sequence completes. Alternatively, for
+     * API level 23 or newer devices, the CANCEL can be used to unlock the camera device
+     * internally locked AE if the application doesn't submit a still capture request after
+     * the AE precapture trigger. Note that, the CANCEL was added in API level 23, and must not
+     * be used in devices that have earlier API levels.</p>
      * <p>The exact effect of auto-exposure (AE) precapture trigger
      * depends on the current AE mode and state; see
      * {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
@@ -740,16 +770,20 @@
      * <ul>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_START START}</li>
+     *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL CANCEL}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
+     * @see CaptureRequest#CONTROL_AE_LOCK
      * @see CaptureResult#CONTROL_AE_STATE
+     * @see CaptureRequest#CONTROL_CAPTURE_INTENT
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
      */
     @PublicKey
     public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
@@ -882,11 +916,29 @@
      * <td align="center">Ready for high-quality capture</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
+     * <td align="center">LOCKED</td>
+     * <td align="center">aeLock is ON and aePrecaptureTrigger is START</td>
+     * <td align="center">LOCKED</td>
+     * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+     * </tr>
+     * <tr>
+     * <td align="center">LOCKED</td>
+     * <td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
+     * <td align="center">LOCKED</td>
+     * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+     * </tr>
+     * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
      * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START</td>
      * <td align="center">PRECAPTURE</td>
      * <td align="center">Start AE precapture metering sequence</td>
      * </tr>
+     * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
+     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL</td>
+     * <td align="center">INACTIVE</td>
+     * <td align="center">Currently active precapture metering sequence is canceled</td>
+     * </tr>
      * </tbody>
      * </table>
      * <p>For the above table, the camera device may skip reporting any state changes that happen
@@ -912,18 +964,30 @@
      * <td align="center">Values are already good, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
+     * <td align="center">Any state (excluding LOCKED)</td>
      * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
      * <td align="center">FLASH_REQUIRED</td>
      * <td align="center">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
+     * <td align="center">Any state (excluding LOCKED)</td>
      * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
      * <td align="center">CONVERGED</td>
      * <td align="center">Converged after a precapture sequence, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
+     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+     * <td align="center">FLASH_REQUIRED</td>
+     * <td align="center">Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.</td>
+     * </tr>
+     * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
+     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+     * <td align="center">CONVERGED</td>
+     * <td align="center">Converged after a precapture sequenceis canceled, transient states are skipped by camera device.</td>
+     * </tr>
+     * <tr>
      * <td align="center">CONVERGED</td>
      * <td align="center">Camera device finished AE scan</td>
      * <td align="center">FLASH_REQUIRED</td>
@@ -1627,7 +1691,7 @@
      * <p>This control (except for MANUAL) is only effective if
      * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
      * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
-     * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains OPAQUE_REPROCESSING. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * contains MANUAL_SENSOR. Other intent values are always supported.</p>
      * <p><b>Possible values:</b>
      * <ul>
@@ -1855,10 +1919,6 @@
      * update, as if this frame is never captured. This mode can be used in the scenario
      * where the application doesn't want a 3A manual control capture to affect
      * the subsequent auto 3A capture results.</p>
-     * <p>LEGACY mode devices will only support AUTO and USE_SCENE_MODE modes.
-     * LIMITED mode devices will only support OFF and OFF_KEEP_STATE if they
-     * support the MANUAL_SENSOR and MANUAL_POST_PROCSESING capabilities.
-     * FULL mode devices will always support OFF and OFF_KEEP_STATE.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #CONTROL_MODE_OFF OFF}</li>
@@ -1866,9 +1926,12 @@
      *   <li>{@link #CONTROL_MODE_USE_SCENE_MODE USE_SCENE_MODE}</li>
      *   <li>{@link #CONTROL_MODE_OFF_KEEP_STATE OFF_KEEP_STATE}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_MODES android.control.availableModes}</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_MODES
      * @see #CONTROL_MODE_OFF
      * @see #CONTROL_MODE_AUTO
      * @see #CONTROL_MODE_USE_SCENE_MODE
@@ -1988,6 +2051,10 @@
      * camera device will use the highest-quality enhancement algorithms,
      * even if it slows down capture rate. FAST means the camera device will
      * not slow down capture rate when applying edge enhancement.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera
+     * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
+     * The camera device may adjust its internal noise reduction parameters for best
+     * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #EDGE_MODE_OFF OFF}</li>
@@ -2003,6 +2070,7 @@
      *
      * @see CameraCharacteristics#EDGE_AVAILABLE_EDGE_MODES
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #EDGE_MODE_OFF
      * @see #EDGE_MODE_FAST
      * @see #EDGE_MODE_HIGH_QUALITY
@@ -2465,18 +2533,28 @@
     /**
      * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>The noise reduction algorithm attempts to improve image quality by removing
-     * excessive noise added by the capture process, especially in dark conditions.
-     * OFF means no noise reduction will be applied by the camera device.</p>
+     * excessive noise added by the capture process, especially in dark conditions.</p>
+     * <p>OFF means no noise reduction will be applied by the camera device, for both raw and
+     * YUV domain.</p>
+     * <p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,to remove
+     * demosaicing or other processing artifacts. For YUV_REPROCESSING, MINIMAL is same as OFF.
+     * This mode is optional, may not be support by all devices. The application should check
+     * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes} before using it.</p>
      * <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
      * will be applied. HIGH_QUALITY mode indicates that the camera device
      * will use the highest-quality noise filtering algorithms,
      * even if it slows down capture rate. FAST means the camera device will not
      * slow down capture rate when applying noise filtering.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera device
+     * will apply FAST/HIGH_QUALITY YUV domain noise reduction, respectively. The camera device
+     * may adjust the noise reduction parameters for best image quality based on the
+     * {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor} if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #NOISE_REDUCTION_MODE_OFF OFF}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_FAST FAST}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #NOISE_REDUCTION_MODE_MINIMAL MINIMAL}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}</p>
@@ -2487,9 +2565,11 @@
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #NOISE_REDUCTION_MODE_OFF
      * @see #NOISE_REDUCTION_MODE_FAST
      * @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
+     * @see #NOISE_REDUCTION_MODE_MINIMAL
      */
     @PublicKey
     public static final Key<Integer> NOISE_REDUCTION_MODE =
@@ -2974,6 +3054,8 @@
      *   <li>{@link #SHADING_MODE_FAST FAST}</li>
      *   <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2982,6 +3064,7 @@
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#SHADING_AVAILABLE_MODES
      * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see #SHADING_MODE_OFF
@@ -3145,7 +3228,7 @@
     /**
      * <p>The shading map is a low-resolution floating-point map
      * that lists the coefficients used to correct for vignetting, for each
-     * Bayer color channel.</p>
+     * Bayer color channel of RAW image data.</p>
      * <p>The least shaded section of the image should have a gain factor
      * of 1; all other sections should have gains above 1.</p>
      * <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
@@ -3181,8 +3264,20 @@
      * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
      * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
      * <p>As a visualization only, inverting the full-color map to recover an
-     * image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
+     * image of a gray wall (using bicubic interpolation for visual quality)
+     * as captured by the sensor gives:</p>
      * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+     * <p>Note that the RAW image data might be subject to lens shading
+     * correction not reported on this map. Query
+     * {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} to see if RAW image data has subject
+     * to lens shading correction. If {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied}
+     * is TRUE, the RAW image data is subject to partial or full lens shading
+     * correction. In the case full lens shading correction is applied to RAW
+     * images, the gain factor map reported in this key will contain all 1.0 gains.
+     * In other words, the map reported in this key is the remaining lens shading
+     * that needs to be applied on the RAW image to get images without lens shading
+     * artifacts. See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image
+     * formats.</p>
      * <p><b>Range of valid values:</b><br>
      * Each gain factor is &gt;= 1</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3192,6 +3287,8 @@
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW
+     * @see CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED
      * @hide
      */
     public static final Key<float[]> STATISTICS_LENS_SHADING_MAP =
@@ -3329,12 +3426,15 @@
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
      */
@@ -3521,6 +3621,8 @@
      *   <li>{@link #TONEMAP_MODE_CONTRAST_CURVE CONTRAST_CURVE}</li>
      *   <li>{@link #TONEMAP_MODE_FAST FAST}</li>
      *   <li>{@link #TONEMAP_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #TONEMAP_MODE_GAMMA_VALUE GAMMA_VALUE}</li>
+     *   <li>{@link #TONEMAP_MODE_PRESET_CURVE PRESET_CURVE}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}</p>
@@ -3536,12 +3638,60 @@
      * @see #TONEMAP_MODE_CONTRAST_CURVE
      * @see #TONEMAP_MODE_FAST
      * @see #TONEMAP_MODE_HIGH_QUALITY
+     * @see #TONEMAP_MODE_GAMMA_VALUE
+     * @see #TONEMAP_MODE_PRESET_CURVE
      */
     @PublicKey
     public static final Key<Integer> TONEMAP_MODE =
             new Key<Integer>("android.tonemap.mode", int.class);
 
     /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * GAMMA_VALUE</p>
+     * <p>The tonemap curve will be defined the following formula:
+     * * OUT = pow(IN, 1.0 / gamma)
+     * where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
+     * pow is the power function and gamma is the gamma value specified by this
+     * key.</p>
+     * <p>The same curve will be applied to all color channels. The camera device
+     * may clip the input gamma value to its supported range. The actual applied
+     * value will be returned in capture result.</p>
+     * <p>The valid range of gamma value varies on different devices, but values
+     * within [1.0, 5.0] are guaranteed not to be clipped.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    @PublicKey
+    public static final Key<Float> TONEMAP_GAMMA =
+            new Key<Float>("android.tonemap.gamma", float.class);
+
+    /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * PRESET_CURVE</p>
+     * <p>The tonemap curve will be defined by specified standard.</p>
+     * <p>sRGB (approximated by 16 control points):</p>
+     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p>Rec. 709 (approximated by 16 control points):</p>
+     * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+     * <p>Note that above figures show a 16 control points approximation of preset
+     * curves. Camera devices may apply a different approximation to the curve.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_SRGB SRGB}</li>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_REC709 REC709}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     * @see #TONEMAP_PRESET_CURVE_SRGB
+     * @see #TONEMAP_PRESET_CURVE_REC709
+     */
+    @PublicKey
+    public static final Key<Integer> TONEMAP_PRESET_CURVE =
+            new Key<Integer>("android.tonemap.presetCurve", int.class);
+
+    /**
      * <p>This LED is nominally used to indicate to the user
      * that the camera is powered on and may be streaming images back to the
      * Application Processor. In certain rare circumstances, the OS may
@@ -3647,6 +3797,52 @@
     public static final Key<Long> SYNC_FRAME_NUMBER =
             new Key<Long>("android.sync.frameNumber", long.class);
 
+    /**
+     * <p>The amount of exposure time increase factor applied to the original output
+     * frame by the application processing before sending for reprocessing.</p>
+     * <p>This is optional, and will be supported if the camera device supports YUV_REPROCESSING
+     * capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains YUV_REPROCESSING).</p>
+     * <p>For some YUV reprocessing use cases, the application may choose to filter the original
+     * output frames to effectively reduce the noise to the same level as a frame that was
+     * captured with longer exposure time. To be more specific, assuming the original captured
+     * images were captured with a sensitivity of S and an exposure time of T, the model in
+     * the camera device is that the amount of noise in the image would be approximately what
+     * would be expected if the original capture parameters had been a sensitivity of
+     * S/effectiveExposureFactor and an exposure time of T*effectiveExposureFactor, rather
+     * than S and T respectively. If the captured images were processed by the application
+     * before being sent for reprocessing, then the application may have used image processing
+     * algorithms and/or multi-frame image fusion to reduce the noise in the
+     * application-processed images (input images). By using the effectiveExposureFactor
+     * control, the application can communicate to the camera device the actual noise level
+     * improvement in the application-processed image. With this information, the camera
+     * device can select appropriate noise reduction and edge enhancement parameters to avoid
+     * excessive noise reduction ({@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}) and insufficient edge
+     * enhancement ({@link CaptureRequest#EDGE_MODE android.edge.mode}) being applied to the reprocessed frames.</p>
+     * <p>For example, for multi-frame image fusion use case, the application may fuse
+     * multiple output frames together to a final frame for reprocessing. When N image are
+     * fused into 1 image for reprocessing, the exposure time increase factor could be up to
+     * square root of N (based on a simple photon shot noise model). The camera device will
+     * adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
+     * produce the best quality images.</p>
+     * <p>This is relative factor, 1.0 indicates the application hasn't processed the input
+     * buffer in a way that affects its effective exposure time.</p>
+     * <p>This control is only effective for YUV reprocessing capture request. For noise
+     * reduction reprocessing, it is only effective when <code>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} != OFF</code>.
+     * Similarly, for edge enhancement reprocessing, it is only effective when
+     * <code>{@link CaptureRequest#EDGE_MODE android.edge.mode} != OFF</code>.</p>
+     * <p><b>Units</b>: Relative exposure time increase factor.</p>
+     * <p><b>Range of valid values:</b><br>
+     * &gt;= 1.0</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    @PublicKey
+    public static final Key<Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR =
+            new Key<Float>("android.reprocess.effectiveExposureFactor", float.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index 6fc99ac..33d539c2 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -530,9 +530,9 @@
         int uPixStride = uPlane.getPixelStride();
 
         byte[] yuvPixel = { 0, 0, 0 };
-        byte[] yFullRow = new byte[yPixStride * width];
-        byte[] uFullRow = new byte[uPixStride * width / 2];
-        byte[] vFullRow = new byte[vPixStride * width / 2];
+        byte[] yFullRow = new byte[yPixStride * (width - 1) + 1];
+        byte[] uFullRow = new byte[uPixStride * (width / 2 - 1) + 1];
+        byte[] vFullRow = new byte[vPixStride * (width / 2 - 1) + 1];
         byte[] finalRow = new byte[BYTES_PER_RGB_PIX * width];
         for (int i = 0; i < height; i++) {
             int halfH = i / 2;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 03540e1..802b938 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -328,15 +328,15 @@
         appendStreamConfig(availableStreamConfigs,
                 ImageFormat.YUV_420_888, previewSizes);
         for (int format : p.getSupportedPreviewFormats()) {
-            if (ImageFormat.isPublicFormat(format)) {
+            if (ImageFormat.isPublicFormat(format) && format != ImageFormat.NV21) {
                 appendStreamConfig(availableStreamConfigs, format, previewSizes);
-            } else {
+            } else if (VERBOSE) {
                 /*
                  *  Do not add any formats unknown to us
                  * (since it would fail runtime checks in StreamConfigurationMap)
                  */
-                Log.w(TAG,
-                        String.format("mapStreamConfigs - Skipping non-public format %x", format));
+                Log.v(TAG,
+                        String.format("mapStreamConfigs - Skipping format %x", format));
             }
         }
 
@@ -389,8 +389,8 @@
             int j = 0;
             for (String mode : antiBandingModes) {
                 int convertedMode = convertAntiBandingMode(mode);
-                if (convertedMode == -1) {
-                    Log.w(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
+                if (VERBOSE && convertedMode == -1) {
+                    Log.v(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
                             " not supported, skipping...");
                 } else {
                     modes[j++] = convertedMode;
@@ -474,6 +474,15 @@
 
             m.set(CONTROL_AE_COMPENSATION_STEP, ParamsUtils.createRational(step));
         }
+
+        /*
+         * control.aeLockAvailable
+         */
+        {
+            boolean aeLockAvailable = p.isAutoExposureLockSupported();
+
+            m.set(CONTROL_AE_LOCK_AVAILABLE, aeLockAvailable);
+        }
     }
 
 
@@ -571,6 +580,16 @@
                 Log.v(TAG, "mapControlAwb - control.awbAvailableModes set to " +
                         ListUtils.listToString(awbAvail));
             }
+
+
+            /*
+             * control.awbLockAvailable
+             */
+            {
+                boolean awbLockAvailable = p.isAutoWhiteBalanceLockSupported();
+
+                m.set(CONTROL_AWB_LOCK_AVAILABLE, awbLockAvailable);
+            }
         }
     }
 
@@ -618,17 +637,44 @@
         /*
          * android.control.availableSceneModes
          */
+        int maxNumDetectedFaces = p.getMaxNumDetectedFaces();
         List<String> sceneModes = p.getSupportedSceneModes();
         List<Integer> supportedSceneModes =
                 ArrayUtils.convertStringListToIntList(sceneModes, sLegacySceneModes, sSceneModes);
-        if (supportedSceneModes == null) { // camera1 doesn't support scene mode settings
-            supportedSceneModes = new ArrayList<Integer>();
-            supportedSceneModes.add(CONTROL_SCENE_MODE_DISABLED); // disabled is always available
+
+        // Special case where the only scene mode listed is AUTO => no scene mode
+        if (sceneModes != null && sceneModes.size() == 1 &&
+                sceneModes.get(0) == Parameters.SCENE_MODE_AUTO) {
+            supportedSceneModes = null;
         }
-        if (p.getMaxNumDetectedFaces() > 0) { // always supports FACE_PRIORITY when face detecting
-            supportedSceneModes.add(CONTROL_SCENE_MODE_FACE_PRIORITY);
+
+        boolean sceneModeSupported = true;
+        if (supportedSceneModes == null && maxNumDetectedFaces == 0) {
+            sceneModeSupported = false;
         }
-        m.set(CONTROL_AVAILABLE_SCENE_MODES, ArrayUtils.toIntArray(supportedSceneModes));
+
+        if (sceneModeSupported) {
+            if (supportedSceneModes == null) {
+                supportedSceneModes = new ArrayList<Integer>();
+            }
+            if (maxNumDetectedFaces > 0) { // always supports FACE_PRIORITY when face detecting
+                supportedSceneModes.add(CONTROL_SCENE_MODE_FACE_PRIORITY);
+            }
+            // Remove all DISABLED occurrences
+            if (supportedSceneModes.contains(CONTROL_SCENE_MODE_DISABLED)) {
+                while(supportedSceneModes.remove(new Integer(CONTROL_SCENE_MODE_DISABLED))) {}
+            }
+            m.set(CONTROL_AVAILABLE_SCENE_MODES, ArrayUtils.toIntArray(supportedSceneModes));
+        } else {
+            m.set(CONTROL_AVAILABLE_SCENE_MODES, new int[] {CONTROL_SCENE_MODE_DISABLED});
+        }
+
+        /*
+         * android.control.availableModes
+         */
+        m.set(CONTROL_AVAILABLE_MODES, sceneModeSupported ?
+                new int[] { CONTROL_MODE_AUTO, CONTROL_MODE_USE_SCENE_MODE } :
+                new int[] { CONTROL_MODE_AUTO });
     }
 
     private static void mapLens(CameraMetadataNative m, Camera.Parameters p) {
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 6535a4e..cf3510d 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -44,6 +44,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import static com.android.internal.util.Preconditions.*;
 
@@ -68,7 +69,7 @@
     // For slightly more spammy messages that will get repeated every frame
     private static final boolean VERBOSE =
             Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.VERBOSE);
-    private final Camera mCamera;
+    private Camera mCamera;
     private final CameraCharacteristics mCharacteristics;
 
     private final CameraDeviceState mDeviceState;
@@ -83,8 +84,8 @@
     private static final int MAX_IN_FLIGHT_REQUESTS = 2;
 
     private static final int PREVIEW_FRAME_TIMEOUT = 1000; // ms
-    private static final int JPEG_FRAME_TIMEOUT = 3000; // ms (same as CTS for API2)
-    private static final int REQUEST_COMPLETE_TIMEOUT = 3000; // ms (same as JPEG timeout)
+    private static final int JPEG_FRAME_TIMEOUT = 4000; // ms (same as CTS for API2)
+    private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT;
 
     private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
     private boolean mPreviewRunning = false;
@@ -108,6 +109,8 @@
     private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");
     private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests");
 
+    private final AtomicBoolean mQuit = new AtomicBoolean(false);
+
     // Stuff JPEGs into HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers to get around SW write
     // limitations for (b/17379185).
     private static final boolean USE_BLOB_FORMAT_OVERRIDE = true;
@@ -325,7 +328,15 @@
             Log.d(TAG, "configureOutputs with " + outputsStr);
         }
 
-        stopPreview();
+        try {
+            stopPreview();
+        }  catch (RuntimeException e) {
+            Log.e(TAG, "Received device exception in configure call: ", e);
+            mDeviceState.setError(
+                    CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
+            return;
+        }
+
         /*
          * Try to release the previous preview's surface texture earlier if we end up
          * using a different one; this also reduces the likelihood of getting into a deadlock
@@ -335,6 +346,11 @@
             mCamera.setPreviewTexture(/*surfaceTexture*/null);
         } catch (IOException e) {
             Log.w(TAG, "Failed to clear prior SurfaceTexture, may cause GL deadlock: ", e);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Received device exception in configure call: ", e);
+            mDeviceState.setError(
+                    CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
+            return;
         }
 
         if (mGLThreadManager != null) {
@@ -470,7 +486,14 @@
             mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
         }
 
-        mCamera.setParameters(mParams);
+        try {
+            mCamera.setParameters(mParams);
+        } catch (RuntimeException e) {
+                Log.e(TAG, "Received device exception while configuring: ", e);
+                mDeviceState.setError(
+                        CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
+
+        }
     }
 
     private void resetJpegSurfaceFormats(Collection<Surface> surfaces) {
@@ -793,7 +816,7 @@
                             }
 
                         } catch (IOException e) {
-                            Log.e(TAG, "Received device exception: ", e);
+                            Log.e(TAG, "Received device exception during capture call: ", e);
                             mDeviceState.setError(
                                     CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
                             break;
@@ -802,6 +825,11 @@
                             mDeviceState.setError(
                                     CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
                             break;
+                        } catch (RuntimeException e) {
+                            Log.e(TAG, "Received device exception during capture call: ", e);
+                            mDeviceState.setError(
+                                    CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
+                            break;
                         }
 
                         if (paramsChanged) {
@@ -878,9 +906,11 @@
                     }
                     if (mGLThreadManager != null) {
                         mGLThreadManager.quit();
+                        mGLThreadManager = null;
                     }
                     if (mCamera != null) {
                         mCamera.release();
+                        mCamera = null;
                     }
                     resetJpegSurfaceFormats(mCallbackOutputs);
                     break;
@@ -942,14 +972,16 @@
      * Quit the request thread, and clean up everything.
      */
     public void quit() {
-        Handler handler = mRequestThread.waitAndGetHandler();
-        handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
-        mRequestThread.quitSafely();
-        try {
-            mRequestThread.join();
-        } catch (InterruptedException e) {
-            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
-                    mRequestThread.getName(), mRequestThread.getId()));
+        if (!mQuit.getAndSet(true)) {  // Avoid sending messages on dead thread's handler.
+            Handler handler = mRequestThread.waitAndGetHandler();
+            handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
+            mRequestThread.quitSafely();
+            try {
+                mRequestThread.join();
+            } catch (InterruptedException e) {
+                Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+                        mRequestThread.getName(), mRequestThread.getId()));
+            }
         }
     }
 
diff --git a/core/java/android/hardware/camera2/utils/ArrayUtils.java b/core/java/android/hardware/camera2/utils/ArrayUtils.java
index 5a78bbd..79a335c 100644
--- a/core/java/android/hardware/camera2/utils/ArrayUtils.java
+++ b/core/java/android/hardware/camera2/utils/ArrayUtils.java
@@ -117,7 +117,7 @@
 
             // Guard against unexpected values
             if (strIndex < 0) {
-                Log.w(TAG, "Ignoring invalid value " + str);
+                if (VERBOSE) Log.v(TAG, "Ignoring invalid value " + str);
                 continue;
             }
 
diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java
index 922b8e7..7e94b89 100644
--- a/core/java/android/hardware/hdmi/HdmiRecordSources.java
+++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java
@@ -759,6 +759,8 @@
      */
     @SystemApi
     public static boolean checkRecordSource(byte[] recordSource) {
+        if (recordSource == null || recordSource.length == 0) return false;
+
         int recordSourceType = recordSource[0];
         int extraDataSize = recordSource.length - 1;
         switch (recordSourceType) {
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 518a874..cc018e9 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -104,7 +104,7 @@
             try {
                 ai = pm.getApplicationInfo(
                         ri.activityInfo.packageName, PackageManager.GET_META_DATA);
-                if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+                if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) {
                     // The application isn't privileged (/system/priv-app).
                     // The enrollment application needs to be a privileged system app.
                     Slog.w(TAG, ai.packageName + "is not a privileged system app");
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f64ef87..f283051 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -68,6 +68,8 @@
      * accessory function is enabled
      * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
      * audio source function is enabled
+     * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
+     * MIDI function is enabled
      * </ul>
      *
      * {@hide}
@@ -188,6 +190,14 @@
     public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
 
     /**
+     * Name of the MIDI USB function.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
+     */
+    public static final String USB_FUNCTION_MIDI = "midi";
+
+    /**
      * Name of the Accessory USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
diff --git a/core/java/android/midi/MidiDevice.java b/core/java/android/midi/MidiDevice.java
index 8aaa86d..b91aedf 100644
--- a/core/java/android/midi/MidiDevice.java
+++ b/core/java/android/midi/MidiDevice.java
@@ -30,6 +30,7 @@
  * This class is used for sending and receiving data to and from an MIDI device
  * Instances of this class are created by {@link MidiManager#openDevice}.
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public final class MidiDevice {
diff --git a/core/java/android/midi/MidiDeviceInfo.java b/core/java/android/midi/MidiDeviceInfo.java
index 5cf62b5..dde2669 100644
--- a/core/java/android/midi/MidiDeviceInfo.java
+++ b/core/java/android/midi/MidiDeviceInfo.java
@@ -28,6 +28,7 @@
  * This class is just an immutable object to encapsulate the MIDI device description.
  * Use the MidiDevice class to actually communicate with devices.
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public class MidiDeviceInfo implements Parcelable {
@@ -45,7 +46,7 @@
     public static final int TYPE_VIRTUAL = 2;
 
     private final int mType;    // USB or virtual
-    private final int mId;  // unique ID generated by MidiService
+    private final int mId;      // unique ID generated by MidiService
     private final int mInputPortCount;
     private final int mOutputPortCount;
     private final Bundle mProperties;
diff --git a/core/java/android/midi/MidiDeviceServer.java b/core/java/android/midi/MidiDeviceServer.java
index ccb2e0c..7499934 100644
--- a/core/java/android/midi/MidiDeviceServer.java
+++ b/core/java/android/midi/MidiDeviceServer.java
@@ -25,7 +25,14 @@
 import java.io.IOException;
 import java.util.ArrayList;
 
-/** @hide */
+/**
+ * This class is used to provide the implemention of MIDI device.
+ * Applications may call {@link MidiManager#createDeviceServer}
+ * to create an instance of this class to implement a virtual MIDI device.
+ *
+ * CANDIDATE FOR PUBLIC API
+ * @hide
+ */
 public final class MidiDeviceServer implements Closeable {
     private static final String TAG = "MidiDeviceServer";
 
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
index 5d806cf8..51c47dd 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/core/java/android/midi/MidiInputPort.java
@@ -26,6 +26,7 @@
 /**
  * This class is used for sending data to a port on a MIDI device
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public class MidiInputPort extends MidiPort implements MidiReceiver {
@@ -33,7 +34,7 @@
     private final FileOutputStream mOutputStream;
 
     // buffer to use for sending messages out our output stream
-    private final byte[] mBuffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+    private final byte[] mBuffer = new byte[MAX_PACKET_SIZE];
 
   /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
         super(portNumber);
@@ -50,10 +51,19 @@
      *                  {@link java.lang.System#nanoTime}
      */
     public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+        assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
+
         synchronized (mBuffer) {
-            int length = packMessage(msg, offset, count, timestamp, mBuffer);
             try {
-                mOutputStream.write(mBuffer, 0, length);
+                while (count > 0) {
+                    int length = packMessage(msg, offset, count, timestamp, mBuffer);
+                    mOutputStream.write(mBuffer, 0, length);
+                    int sent = getMessageSize(mBuffer, length);
+                    assert(sent >= 0 && sent <= length);
+
+                    offset += sent;
+                    count -= sent;
+                }
             } catch (IOException e) {
                 IoUtils.closeQuietly(mOutputStream);
                 // report I/O failure
diff --git a/core/java/android/midi/MidiManager.java b/core/java/android/midi/MidiManager.java
index 2c1c7bf..8aa8395 100644
--- a/core/java/android/midi/MidiManager.java
+++ b/core/java/android/midi/MidiManager.java
@@ -35,6 +35,7 @@
  * {@samplecode
  * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);}
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public class MidiManager {
@@ -184,7 +185,7 @@
      * @param properties a {@link android.os.Bundle} containing properties describing the device
      * @param isPrivate true if this device should only be visible and accessible to apps
      *                  with the same UID as the caller
-     * @return a {@link MidiVirtualDevice} object to locally represent the device
+     * @return a {@link MidiDeviceServer} object to locally represent the device
      */
     public MidiDeviceServer createDeviceServer(int numInputPorts, int numOutputPorts,
             Bundle properties, boolean isPrivate) {
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
index b550ed4..332b431 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -26,8 +26,9 @@
 import java.util.ArrayList;
 
 /**
- * This class is used for receiving data to a port on a MIDI device
+ * This class is used for receiving data from a port on a MIDI device
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public class MidiOutputPort extends MidiPort implements MidiSender {
@@ -45,7 +46,7 @@
     private final Thread mThread = new Thread() {
         @Override
         public void run() {
-            byte[] buffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+            byte[] buffer = new byte[MAX_PACKET_SIZE];
             ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
 
             try {
@@ -54,9 +55,6 @@
                     int count = mInputStream.read(buffer);
                     if (count < 0) {
                         break;
-                    } else if (count < MIN_PACKED_MESSAGE_SIZE || count > MAX_PACKED_MESSAGE_SIZE) {
-                        Log.e(TAG, "Number of bytes read out of range: " + count);
-                        continue;
                     }
 
                     int offset = getMessageOffset(buffer, count);
@@ -88,15 +86,15 @@
                     }
                 }
             } catch (IOException e) {
-                Log.e(TAG, "read failed");
                 // report I/O failure
+                Log.e(TAG, "read failed");
+            } finally {
                 IoUtils.closeQuietly(mInputStream);
                 onIOException();
             }
         }
     };
 
-
   /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
         super(portNumber);
         mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
diff --git a/core/java/android/midi/MidiPort.java b/core/java/android/midi/MidiPort.java
index 1fa7946..7512a90 100644
--- a/core/java/android/midi/MidiPort.java
+++ b/core/java/android/midi/MidiPort.java
@@ -24,6 +24,7 @@
  * This class represents a MIDI input or output port.
  * Base class for {@link MidiInputPort} and {@link MidiOutputPort}
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 abstract public class MidiPort implements Closeable {
@@ -32,16 +33,19 @@
     private final int mPortNumber;
 
     /**
-     * Minimum size of packed message as sent through our ParcelFileDescriptor
-     * 8 bytes for timestamp and 1 to 3 bytes for message
+     * Maximum size of a packet that can pass through our ParcelFileDescriptor
      */
-    protected static final int MIN_PACKED_MESSAGE_SIZE = 9;
+    protected static final int MAX_PACKET_SIZE = 1024;
 
     /**
-     * Maximum size of packed message as sent through our ParcelFileDescriptor
-     * 8 bytes for timestamp and 1 to 3 bytes for message
+     * size of message timestamp in bytes
      */
-    protected static final int MAX_PACKED_MESSAGE_SIZE = 11;
+    private static final int TIMESTAMP_SIZE = 8;
+
+    /**
+     * Maximum amount of MIDI data that can be included in a packet
+     */
+    public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
 
 
   /* package */ MidiPort(int portNumber) {
@@ -76,49 +80,52 @@
      */
     protected static int packMessage(byte[] message, int offset, int size, long timestamp,
             byte[] dest) {
-        // pack variable length message first
+        if (size + TIMESTAMP_SIZE > MAX_PACKET_SIZE) {
+            size = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+        }
+        // message data goes first
         System.arraycopy(message, offset, dest, 0, size);
-        int destOffset = size;
-        // timestamp takes 8 bytes
-        for (int i = 0; i < 8; i++) {
-            dest[destOffset++] = (byte)timestamp;
+
+        // followed by timestamp
+        for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+            dest[size++] = (byte)timestamp;
             timestamp >>= 8;
         }
 
-        return destOffset;
+        return size;
     }
 
     /**
-     * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
-     * returns the offet of of MIDI message in packed buffer
+     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * returns the offset of the MIDI message in packed buffer
      */
     protected static int getMessageOffset(byte[] buffer, int bufferLength) {
-        // message is at start of buffer
+        // message is at the beginning
         return 0;
     }
 
     /**
-     * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
-     * returns size of MIDI message in packed buffer
+     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * returns size of MIDI data in packed buffer
      */
     protected static int getMessageSize(byte[] buffer, int bufferLength) {
-        // message length is total buffer length minus size of the timestamp and port number
-        return bufferLength - 8 /* sizeof(timestamp) */;
+        // message length is total buffer length minus size of the timestamp
+        return bufferLength - TIMESTAMP_SIZE;
     }
 
     /**
-     * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * unpacks timestamp from packed buffer
      */
     protected static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+        // timestamp is at end of the packet
+        int offset = bufferLength;
         long timestamp = 0;
 
-        // timestamp follows variable length message data
-        int dataLength = getMessageSize(buffer, bufferLength);
-        for (int i = dataLength + 7; i >= dataLength; i--) {
-            int b = (int)buffer[i] & 0xFF;
+        for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+            int b = (int)buffer[--offset] & 0xFF;
             timestamp = (timestamp << 8) | b;
         }
         return timestamp;
-     }
+    }
 }
diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java
index 0b183cc..fdfe51a 100644
--- a/core/java/android/midi/MidiReceiver.java
+++ b/core/java/android/midi/MidiReceiver.java
@@ -19,21 +19,24 @@
 import java.io.IOException;
 
 /**
- * Interface for receiving events from a MIDI device.
+ * Interface for receiving data from a MIDI device.
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public interface MidiReceiver {
     /**
-     * Called to pass a MIDI event to the receiver.
+     * Called to pass MIDI data to the receiver.
      *
      * NOTE: the msg array parameter is only valid within the context of this call.
      * The msg bytes should be copied by the receiver rather than retaining a reference
      * to this parameter.
+     * Also, modifying the contents of the msg array parameter may result in other receivers
+     * in the same application receiving incorrect values in their onPost() method.
      *
-     * @param msg a byte array containing the MIDI message
-     * @param offset the offset of the first byte of the message in the byte array
-     * @param count the number of bytes in the message
+     * @param msg a byte array containing the MIDI data
+     * @param offset the offset of the first byte of the data in the byte array
+     * @param count the number of bytes of MIDI data in the array
      * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
      * @throws IOException
      */
diff --git a/core/java/android/midi/MidiSender.java b/core/java/android/midi/MidiSender.java
index 7958a06..2b7afad 100644
--- a/core/java/android/midi/MidiSender.java
+++ b/core/java/android/midi/MidiSender.java
@@ -20,6 +20,7 @@
  * Interface provided by a device to allow attaching
  * MidiReceivers to a MIDI device.
  *
+ * CANDIDATE FOR PUBLIC API
  * @hide
  */
 public interface MidiSender {
diff --git a/core/java/android/midi/MidiUtils.java b/core/java/android/midi/MidiUtils.java
deleted file mode 100644
index e60e2db..0000000
--- a/core/java/android/midi/MidiUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.midi;
-
-import android.util.Log;
-
-/**
- * Class containing miscellaneous MIDI utilities.
- *
- * @hide
- */
-public final class MidiUtils {
-    private static final String TAG = "MidiUtils";
-
-    private MidiUtils() { }
-
-    /**
-     * Returns data size of a MIDI message based on the message's command byte
-     * @param b the message command byte
-     * @return the message's data length
-     */
-    public static int getMessageDataSize(byte b) {
-        switch (b & 0xF0) {
-            case 0x80:
-            case 0x90:
-            case 0xA0:
-            case 0xB0:
-            case 0xE0:
-                return 2;
-            case 0xC0:
-            case 0xD0:
-                return 1;
-            case 0xF0:
-                switch (b & 0x0F) {
-                    case 0x00:
-                        Log.e(TAG, "System Exclusive not supported yet");
-                        return -1;
-                    case 0x01:
-                    case 0x03:
-                        return 1;
-                    case 0x02:
-                        return 2;
-                    default:
-                        return 0;
-                }
-            default:
-                Log.e(TAG, "unknown MIDI command " + b);
-                return -1;
-        }
-    }
-}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1a51808..808be21 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2371,6 +2371,10 @@
      * The lookup key for a {@link Network} object included with the intent after
      * successfully finding a network for the applications request.  Retrieve it with
      * {@link android.content.Intent#getParcelableExtra(String)}.
+     * <p>
+     * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+     * {@link Network#openConnection(java.net.URL)} then you must get a
+     * ConnectivityManager instance before doing so.
      */
     public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
 
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
index 8626d08..9bdf4f6 100644
--- a/core/java/android/net/PacProxySelector.java
+++ b/core/java/android/net/PacProxySelector.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
@@ -74,8 +73,8 @@
         }
         try {
             response = mProxyService.resolvePacFile(uri.getHost(), urlString);
-        } catch (RemoteException e) {
-            e.printStackTrace();
+        } catch (Exception e) {
+            Log.e(TAG, "Error resolving PAC File", e);
         }
         if (response == null) {
             return mDefaultList;
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 6654577..27096b1 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -159,6 +159,8 @@
      *     instead. The Apache HTTP client is no longer maintained and may be removed in a future
      *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
      *     for further details.
+     *
+     * @removed
      */
     @Deprecated
     public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 365f2b6..37ee961 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -188,6 +188,7 @@
         for (InetAddress dnsServer : dnsServers) {
             NetworkUtils.parcelInetAddress(dest, dnsServer, flags);
         }
+        dest.writeString(domains);
     }
 
     protected static void readFromParcel(StaticIpConfiguration s, Parcel in) {
@@ -198,5 +199,6 @@
         for (int i = 0; i < size; i++) {
             s.dnsServers.add(NetworkUtils.unparcelInetAddress(in));
         }
+        s.domains = in.readString();
     }
 }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 2099c3f..bf3d9aa 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,6 +366,7 @@
     public String toSafeString() {
         String scheme = getScheme();
         String ssp = getSchemeSpecificPart();
+        String authority = null;
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -384,6 +385,9 @@
                     }
                 }
                 return builder.toString();
+            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
+                ssp = null;
+                authority = "//" + getAuthority() + "/...";
             }
         }
         // Not a sensitive scheme, but let's still be conservative about
@@ -397,6 +401,9 @@
         if (ssp != null) {
             builder.append(ssp);
         }
+        if (authority != null) {
+            builder.append(authority);
+        }
         return builder.toString();
     }
 
@@ -1742,7 +1749,7 @@
      *
      * @return normalized Uri (never null)
      * @see {@link android.content.Intent#setData}
-     * @see {@link #setNormalizedData}
+     * @see {@link android.content.Intent#setDataAndNormalize}
      */
     public Uri normalizeScheme() {
         String scheme = getScheme();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 2dfd919..eb86e7e 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -597,6 +597,11 @@
          * Lollipop with an extra sugar coating on the outside!
          */
         public static final int LOLLIPOP_MR1 = 22;
+
+        /**
+         * M comes after L.
+         */
+        public static final int MNC = CUR_DEVELOPMENT;
     }
 
     /** The type of build, like "user" or "eng". */
@@ -645,15 +650,22 @@
     }
 
     /**
-     * Check that device fingerprint is defined and that it matches across
-     * various partitions.
+     * Verifies the the current flash of the device is consistent with what
+     * was expected at build time.
+     * 1) Checks that device fingerprint is defined and that it matches across
+     *    various partitions.
+     * 2) Verifies radio and bootloader partitions are those expected in the build.
      *
      * @hide
      */
-    public static boolean isFingerprintConsistent() {
+    public static boolean isBuildConsistent() {
         final String system = SystemProperties.get("ro.build.fingerprint");
         final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
         final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
+        final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
+        final String currentBootloader = SystemProperties.get("ro.bootloader");
+        final String requiredRadio = SystemProperties.get("ro.build.expect.baseband");
+        final String currentRadio = SystemProperties.get("gsm.version.baseband");
 
         if (TextUtils.isEmpty(system)) {
             Slog.e(TAG, "Required ro.build.fingerprint is empty!");
@@ -676,6 +688,22 @@
             }
         }
 
+        if (!TextUtils.isEmpty(requiredBootloader)) {
+            if (!Objects.equals(currentBootloader, requiredBootloader)) {
+                Slog.e(TAG, "Mismatched bootloader version: build requires " + requiredBootloader
+                        + " but runtime reports " + currentBootloader);
+                return false;
+            }
+        }
+
+        if (!TextUtils.isEmpty(requiredRadio)) {
+            if (!Objects.equals(currentRadio, requiredRadio)) {
+                Slog.e(TAG, "Mismatched radio version: build requires " + requiredRadio
+                        + " but runtime reports " + currentRadio);
+                return false;
+            }
+        }
+
         return true;
     }
 
diff --git a/core/java/android/os/IProcessInfoService.aidl b/core/java/android/os/IProcessInfoService.aidl
new file mode 100644
index 0000000..c98daa2
--- /dev/null
+++ b/core/java/android/os/IProcessInfoService.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IProcessInfoService
+{
+    /**
+     * For each PID in the given input array, write the current process state
+     * for that process into the output array, or ActivityManager.PROCESS_STATE_NONEXISTENT
+     * to indicate that no process with the given PID exists.
+     */
+    void getProcessStatesFromPids(in int[] pids, out int[] states);
+}
+
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index bedc695..3d5215b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -276,7 +276,7 @@
 
     private static native byte[] nativeMarshall(long nativePtr);
     private static native void nativeUnmarshall(
-            long nativePtr, byte[] data, int offest, int length);
+            long nativePtr, byte[] data, int offset, int length);
     private static native void nativeAppendFrom(
             long thisNativePtr, long otherNativePtr, int offset, int length);
     private static native boolean nativeHasFileDescriptors(long nativePtr);
@@ -438,8 +438,8 @@
     /**
      * Set the bytes in data to be the raw bytes of this Parcel.
      */
-    public final void unmarshall(byte[] data, int offest, int length) {
-        nativeUnmarshall(mNativePtr, data, offest, length);
+    public final void unmarshall(byte[] data, int offset, int length) {
+        nativeUnmarshall(mNativePtr, data, offset, length);
     }
 
     public final void appendFrom(Parcel parcel, int offset, int length) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8307d9b..d52dd30 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -835,6 +835,21 @@
     }
 
     /**
+     * Turn off the device.
+     *
+     * @param confirm If true, shows a shutdown confirmation dialog.
+     * @param wait If true, this call waits for the shutdown to complete and does not return.
+     *
+     * @hide
+     */
+    public void shutdown(boolean confirm, boolean wait) {
+        try {
+            mService.shutdown(confirm, wait);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
      * This broadcast is only sent to registered receivers.
      */
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 30f0c6a..90d30d6 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -45,11 +45,22 @@
     private static final int VALID_COLOR_MODES =
             COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
 
+    /** Duplex mode: No duplexing. */
+    public static final int DUPLEX_MODE_NONE = 1 << 0;
+    /** Duplex mode: Pages are turned sideways along the long edge - like a book. */
+    public static final int DUPLEX_MODE_LONG_EDGE = 1 << 1;
+    /** Duplex mode: Pages are turned upwards along the short edge - like a notpad. */
+    public static final int DUPLEX_MODE_SHORT_EDGE = 1 << 2;
+
+    private static final int VALID_DUPLEX_MODES =
+            DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
+
     private MediaSize mMediaSize;
     private Resolution mResolution;
     private Margins mMinMargins;
 
     private int mColorMode;
+    private int mDuplexMode = DUPLEX_MODE_NONE;
 
     PrintAttributes() {
         /* hide constructor */
@@ -60,6 +71,7 @@
         mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
         mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
         mColorMode = parcel.readInt();
+        mDuplexMode = parcel.readInt();
     }
 
     /**
@@ -74,7 +86,7 @@
     /**
      * Sets the media size.
      *
-     * @param The media size.
+     * @param mediaSize The media size.
      *
      * @hide
      */
@@ -94,7 +106,7 @@
     /**
      * Sets the resolution.
      *
-     * @param The resolution.
+     * @param resolution The resolution.
      *
      * @hide
      */
@@ -130,7 +142,7 @@
      * </strong>
      * </p>
      *
-     * @param The margins.
+     * @param margins The margins.
      *
      * @hide
      */
@@ -153,7 +165,7 @@
     /**
      * Sets the color mode.
      *
-     * @param The color mode.
+     * @param colorMode The color mode.
      *
      * @see #COLOR_MODE_MONOCHROME
      * @see #COLOR_MODE_COLOR
@@ -179,6 +191,35 @@
     }
 
     /**
+     * Gets the duplex mode.
+     *
+     * @return The duplex mode.
+     *
+     * @see #DUPLEX_MODE_NONE
+     * @see #DUPLEX_MODE_LONG_EDGE
+     * @see #DUPLEX_MODE_SHORT_EDGE
+     */
+    public int getDuplexMode() {
+        return mDuplexMode;
+    }
+
+    /**
+     * Sets the duplex mode.
+     *
+     * @param duplexMode The duplex mode.
+     *
+     * @see #DUPLEX_MODE_NONE
+     * @see #DUPLEX_MODE_LONG_EDGE
+     * @see #DUPLEX_MODE_SHORT_EDGE
+     *
+     * @hide
+     */
+    public void setDuplexMode(int duplexMode) {
+        enforceValidDuplexMode(duplexMode);
+        mDuplexMode = duplexMode;
+    }
+
+    /**
      * Gets a new print attributes instance which is in portrait orientation,
      * which is the media size is in portrait and all orientation dependent
      * attributes such as resolution and margins are properly adjusted.
@@ -211,6 +252,7 @@
         attributes.setMinMargins(getMinMargins());
 
         attributes.setColorMode(getColorMode());
+        attributes.setDuplexMode(getDuplexMode());
 
         return attributes;
     }
@@ -248,6 +290,7 @@
         attributes.setMinMargins(getMinMargins());
 
         attributes.setColorMode(getColorMode());
+        attributes.setDuplexMode(getDuplexMode());
 
         return attributes;
     }
@@ -273,6 +316,7 @@
             parcel.writeInt(0);
         }
         parcel.writeInt(mColorMode);
+        parcel.writeInt(mDuplexMode);
     }
 
     @Override
@@ -285,6 +329,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + mColorMode;
+        result = prime * result + mDuplexMode;
         result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
         result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
         result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
@@ -306,6 +351,9 @@
         if (mColorMode != other.mColorMode) {
             return false;
         }
+        if (mDuplexMode != other.mDuplexMode) {
+            return false;
+        }
         if (mMinMargins == null) {
             if (other.mMinMargins != null) {
                 return false;
@@ -344,6 +392,7 @@
         builder.append(", resolution: ").append(mResolution);
         builder.append(", minMargins: ").append(mMinMargins);
         builder.append(", colorMode: ").append(colorModeToString(mColorMode));
+        builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode));
         builder.append("}");
         return builder.toString();
     }
@@ -354,6 +403,7 @@
         mResolution = null;
         mMinMargins = null;
         mColorMode = 0;
+        mDuplexMode = DUPLEX_MODE_NONE;
     }
 
     /**
@@ -364,6 +414,7 @@
         mResolution = other.mResolution;
         mMinMargins = other.mMinMargins;
         mColorMode = other.mColorMode;
+        mDuplexMode = other.mDuplexMode;
     }
 
     /**
@@ -1270,17 +1321,41 @@
             case COLOR_MODE_COLOR: {
                 return "COLOR_MODE_COLOR";
             }
-            default:
+            default: {
                 return "COLOR_MODE_UNKNOWN";
+            }
+        }
+    }
+
+    static String duplexModeToString(int duplexMode) {
+        switch (duplexMode) {
+            case DUPLEX_MODE_NONE: {
+                return "DUPLEX_MODE_NONE";
+            }
+            case DUPLEX_MODE_LONG_EDGE: {
+                return "DUPLEX_MODE_LONG_EDGE";
+            }
+            case DUPLEX_MODE_SHORT_EDGE: {
+                return "DUPLEX_MODE_SHORT_EDGE";
+            }
+            default: {
+                return "DUPLEX_MODE_UNKNOWN";
+            }
         }
     }
 
     static void enforceValidColorMode(int colorMode) {
-        if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
+        if ((colorMode & VALID_COLOR_MODES) == 0 || Integer.bitCount(colorMode) != 1) {
             throw new IllegalArgumentException("invalid color mode: " + colorMode);
         }
     }
 
+    static void enforceValidDuplexMode(int duplexMode) {
+        if ((duplexMode & VALID_DUPLEX_MODES) == 0 || Integer.bitCount(duplexMode) != 1) {
+            throw new IllegalArgumentException("invalid duplex mode: " + duplexMode);
+        }
+    }
+
     /**
      * Builder for creating {@link PrintAttributes}.
      */
@@ -1331,15 +1406,31 @@
          * @see PrintAttributes#COLOR_MODE_COLOR
          */
         public Builder setColorMode(int colorMode) {
-            if (Integer.bitCount(colorMode) > 1) {
-                throw new IllegalArgumentException("can specify at most one colorMode bit.");
-            }
             mAttributes.setColorMode(colorMode);
             return this;
         }
 
         /**
+         * Sets the duplex mode.
+         *
+         * @param duplexMode A valid duplex mode or zero.
+         * @return This builder.
+         *
+         * @see PrintAttributes#DUPLEX_MODE_NONE
+         * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
+         * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
+         */
+        public Builder setDuplexMode(int duplexMode) {
+            mAttributes.setDuplexMode(duplexMode);
+            return this;
+        }
+
+        /**
          * Creates a new {@link PrintAttributes} instance.
+         * <p>
+         * If you do not specify a duplex mode, the default
+         * {@link #DUPLEX_MODE_NONE} will be used.
+         * </p>
          *
          * @return The new instance.
          */
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index 806a89d8..96f3185 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -47,7 +47,8 @@
     private static final int PROPERTY_MEDIA_SIZE = 0;
     private static final int PROPERTY_RESOLUTION = 1;
     private static final int PROPERTY_COLOR_MODE = 2;
-    private static final int PROPERTY_COUNT = 3;
+    private static final int PROPERTY_DUPLEX_MODE = 3;
+    private static final int PROPERTY_COUNT = 4;
 
     private static final Margins DEFAULT_MARGINS = new Margins(0,  0,  0,  0);
 
@@ -56,6 +57,7 @@
     private List<Resolution> mResolutions;
 
     private int mColorModes;
+    private int mDuplexModes;
 
     private final int[] mDefaults = new int[PROPERTY_COUNT];
 
@@ -106,6 +108,7 @@
         }
 
         mColorModes = other.mColorModes;
+        mDuplexModes = other.mDuplexModes;
 
         final int defaultCount = other.mDefaults.length;
         for (int i = 0; i < defaultCount; i++) {
@@ -154,6 +157,19 @@
     }
 
     /**
+     * Gets the bit mask of supported duplex modes.
+     *
+     * @return The bit mask of supported duplex modes.
+     *
+     * @see PrintAttributes#DUPLEX_MODE_NONE
+     * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
+     * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
+     */
+    public int getDuplexModes() {
+        return mDuplexModes;
+    }
+
+    /**
      * Gets the default print attributes.
      *
      * @return The default attributes.
@@ -178,6 +194,11 @@
             builder.setColorMode(colorMode);
         }
 
+        final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE];
+        if (duplexMode > 0) {
+            builder.setDuplexMode(duplexMode);
+        }
+
         return builder.build();
     }
 
@@ -187,6 +208,7 @@
         readResolutions(parcel);
 
         mColorModes = parcel.readInt();
+        mDuplexModes = parcel.readInt();
 
         readDefaults(parcel);
     }
@@ -203,6 +225,7 @@
         writeResolutions(parcel);
 
         parcel.writeInt(mColorModes);
+        parcel.writeInt(mDuplexModes);
 
         writeDefaults(parcel);
     }
@@ -215,6 +238,7 @@
         result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
         result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
         result = prime * result + mColorModes;
+        result = prime * result + mDuplexModes;
         result = prime * result + Arrays.hashCode(mDefaults);
         return result;
     }
@@ -255,6 +279,9 @@
         if (mColorModes != other.mColorModes) {
             return false;
         }
+        if (mDuplexModes != other.mDuplexModes) {
+            return false;
+        }
         if (!Arrays.equals(mDefaults, other.mDefaults)) {
             return false;
         }
@@ -269,6 +296,7 @@
         builder.append(", mediaSizes=").append(mMediaSizes);
         builder.append(", resolutions=").append(mResolutions);
         builder.append(", colorModes=").append(colorModesToString());
+        builder.append(", duplexModes=").append(duplexModesToString());
         builder.append("\"}");
         return builder.toString();
     }
@@ -289,6 +317,22 @@
         return builder.toString();
     }
 
+    private String duplexModesToString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append('[');
+        int duplexModes = mDuplexModes;
+        while (duplexModes != 0) {
+            final int duplexMode = 1 << Integer.numberOfTrailingZeros(duplexModes);
+            duplexModes &= ~duplexMode;
+            if (builder.length() > 1) {
+                builder.append(", ");
+            }
+            builder.append(PrintAttributes.duplexModeToString(duplexMode));
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
     private void writeMediaSizes(Parcel parcel) {
         if (mMediaSizes == null) {
             parcel.writeInt(0);
@@ -495,19 +539,51 @@
                 currentModes &= ~currentMode;
                 PrintAttributes.enforceValidColorMode(currentMode);
             }
-            if ((colorModes & defaultColorMode) == 0) {
-                throw new IllegalArgumentException("Default color mode not in color modes.");
-            }
-            PrintAttributes.enforceValidColorMode(colorModes);
+            PrintAttributes.enforceValidColorMode(defaultColorMode);
             mPrototype.mColorModes = colorModes;
             mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
             return this;
         }
 
         /**
+         * Sets the duplex modes.
+         * <p>
+         * <strong>Required:</strong> No
+         * </p>
+         *
+         * @param duplexModes The duplex mode bit mask.
+         * @param defaultDuplexMode The default duplex mode.
+         * @return This builder.
+         *
+         * @throws IllegalArgumentException If duplex modes contains an invalid
+         *         mode bit or if the default duplex mode is invalid.
+         *
+         * @see PrintAttributes#DUPLEX_MODE_NONE
+         * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
+         * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
+         */
+        public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) {
+            int currentModes = duplexModes;
+            while (currentModes > 0) {
+                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
+                currentModes &= ~currentMode;
+                PrintAttributes.enforceValidDuplexMode(currentMode);
+            }
+            PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
+            mPrototype.mDuplexModes = duplexModes;
+            mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
+            return this;
+        }
+
+        /**
          * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
          * required properties have been specified. See individual methods
          * in this class for reference about required attributes.
+         * <p>
+         * <strong>Note:</strong> If you do not add supported duplex modes,
+         * {@link android.print.PrintAttributes#DUPLEX_MODE_NONE} will set
+         * as the only supported mode and also as the default duplex mode.
+         * </p>
          *
          * @return A new {@link PrinterCapabilitiesInfo}.
          *
@@ -532,6 +608,10 @@
             if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
                 throw new IllegalStateException("No default color mode specified.");
             }
+            if (mPrototype.mDuplexModes == 0) {
+                setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
+                        PrintAttributes.DUPLEX_MODE_NONE);
+            }
             if (mPrototype.mMinMargins == null) {
                 throw new IllegalArgumentException("margins cannot be null");
             }
@@ -558,4 +638,3 @@
         }
     };
 }
-
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index ae95854..7ed1649 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -192,7 +192,7 @@
 
     /**
      * If you declared an optional activity with advanced print options via the
-     * {@link R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
      * attribute, this extra is used to pass in the currently constructed {@link
      * PrintJobInfo} to your activity allowing you to modify it. After you are
      * done, you must return the modified {@link PrintJobInfo} via the same extra.
@@ -224,7 +224,7 @@
 
     /**
      * If you declared an optional activity with advanced print options via the
-     * {@link R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
      * attribute, this extra is used to pass in the currently selected printer's
      * {@link android.print.PrinterInfo} to your activity allowing you to inspect it.
      *
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 7dd559c..67ac043 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1434,9 +1434,9 @@
         * and {@link #CONTENT_MULTI_VCARD_URI} to indicate that the returned
         * vcard should not contain a photo.
         *
-        * @hide
+        * This is useful for obtaining a space efficient vcard.
         */
-        public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "nophoto";
+        public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
 
         /**
          * Base {@link Uri} for referencing multiple {@link Contacts} entry,
@@ -2194,6 +2194,16 @@
         public static final String CONTACT_ID = "contact_id";
 
         /**
+         * Persistent unique id for each raw_contact within its account.
+         * This id is provided by its own data source, and can be used to backup metadata
+         * to the server.
+         * This should be unique within each set of account_name/account_type/data_set
+         *
+         * @hide
+         */
+        public static final String BACKUP_ID = "backup_id";
+
+        /**
          * The data set within the account that this row belongs to.  This allows
          * multiple sync adapters for the same account type to distinguish between
          * each others' data.
@@ -2238,33 +2248,6 @@
         public static final String DELETED = "deleted";
 
         /**
-         * The "name_verified" flag: "1" means that the name fields on this raw
-         * contact can be trusted and therefore should be used for the entire
-         * aggregated contact.
-         * <p>
-         * If an aggregated contact contains more than one raw contact with a
-         * verified name, one of those verified names is chosen at random.
-         * If an aggregated contact contains no verified names, the
-         * name is chosen randomly from the constituent raw contacts.
-         * </p>
-         * <p>
-         * Updating this flag from "0" to "1" automatically resets it to "0" on
-         * all other raw contacts in the same aggregated contact.
-         * </p>
-         * <p>
-         * Sync adapters should only specify a value for this column when
-         * inserting a raw contact and leave it out when doing an update.
-         * </p>
-         * <p>
-         * The default value is "0"
-         * </p>
-         * <p>Type: INTEGER</p>
-         *
-         * @hide
-         */
-        public static final String NAME_VERIFIED = "name_verified";
-
-        /**
          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
          * <P>Type: INTEGER</P>
@@ -2960,7 +2943,6 @@
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
-                DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, NAME_VERIFIED);
                 android.content.Entity contact = new android.content.Entity(cv);
 
                 // read data rows until the contact id changes
@@ -3986,6 +3968,13 @@
         public static final String MIMETYPE = "mimetype";
 
         /**
+         * Hash id on the data fields, used for backup and restore.
+         *
+         * @hide
+         */
+        public static final String HASH_ID = "hash_id";
+
+        /**
          * A reference to the {@link RawContacts#_ID}
          * that this data belongs to.
          */
@@ -8072,8 +8061,10 @@
         public static final String EXTRA_TARGET_RECT = "android.provider.extra.TARGET_RECT";
 
         /**
-         * Extra used to specify size of pivot dialog.
-         * @hide
+         * Extra used to specify size of QuickContacts. Not all implementations of QuickContacts
+         * will respect this extra's value.
+         *
+         * One of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
          */
         public static final String EXTRA_MODE = "android.provider.extra.MODE";
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e055203..c836a33 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.app.SearchManager;
 import android.app.WallpaperManager;
 import android.content.ComponentName;
@@ -50,14 +51,21 @@
 import android.speech.tts.TextToSpeech;
 import android.text.TextUtils;
 import android.util.AndroidException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.ILockSettings;
 
 import java.net.URISyntaxException;
+import java.text.SimpleDateFormat;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
 
 /**
  * The Settings provider contains global system-level device preferences.
@@ -1191,6 +1199,11 @@
     public static final class System extends NameValueTable {
         public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
 
+        /** @hide */
+        public static interface Validator {
+            public boolean validate(String value);
+        }
+
         /**
          * The content:// style URL for this table
          */
@@ -1293,13 +1306,56 @@
             MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
         }
 
+        private static final Validator sBooleanValidator =
+                new DiscreteValueValidator(new String[] {"0", "1"});
+
+        private static final Validator sNonNegativeIntegerValidator = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    return Integer.parseInt(value) >= 0;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        };
+
+        private static final Validator sVolumeValidator =
+                new InclusiveFloatRangeValidator(0, 1);
+
+        private static final Validator sUriValidator = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    Uri.decode(value);
+                    return true;
+                } catch (IllegalArgumentException e) {
+                    return false;
+                }
+            }
+        };
+
+        private static final Validator sLenientIpAddressValidator = new Validator() {
+            private static final int MAX_IPV6_LENGTH = 45;
+
+            @Override
+            public boolean validate(String value) {
+                return value.length() <= MAX_IPV6_LENGTH;
+            }
+        };
+
         /** @hide */
-        public static void getMovedKeys(HashSet<String> outKeySet) {
+        public static void getMovedToGlobalSettings(Set<String> outKeySet) {
             outKeySet.addAll(MOVED_TO_GLOBAL);
             outKeySet.addAll(MOVED_TO_SECURE_THEN_GLOBAL);
         }
 
         /** @hide */
+        public static void getMovedToSecureSettings(Set<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_SECURE);
+        }
+
+        /** @hide */
         public static void getNonLegacyMovedKeys(HashSet<String> outKeySet) {
             outKeySet.addAll(MOVED_TO_GLOBAL);
         }
@@ -1722,6 +1778,56 @@
             putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle);
         }
 
+        private static final class DiscreteValueValidator implements Validator {
+            private final String[] mValues;
+
+            public DiscreteValueValidator(String[] values) {
+                mValues = values;
+            }
+
+            public boolean validate(String value) {
+                return ArrayUtils.contains(mValues, value);
+            }
+        }
+
+        private static final class InclusiveIntegerRangeValidator implements Validator {
+            private final int mMin;
+            private final int mMax;
+
+            public InclusiveIntegerRangeValidator(int min, int max) {
+                mMin = min;
+                mMax = max;
+            }
+
+            public boolean validate(String value) {
+                try {
+                    final int intValue = Integer.parseInt(value);
+                    return intValue >= mMin && intValue <= mMax;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        }
+
+        private static final class InclusiveFloatRangeValidator implements Validator {
+            private final float mMin;
+            private final float mMax;
+
+            public InclusiveFloatRangeValidator(float min, float max) {
+                mMin = min;
+                mMax = max;
+            }
+
+            public boolean validate(String value) {
+                try {
+                    final float floatValue = Float.parseFloat(value);
+                    return floatValue >= mMin && floatValue <= mMax;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        }
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
          */
@@ -1740,6 +1846,9 @@
          */
         public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
 
+        private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 3);
+
         /**
          * END_BUTTON_BEHAVIOR value for "go home".
          * @hide
@@ -1764,6 +1873,8 @@
          */
         public static final String ADVANCED_SETTINGS = "advanced_settings";
 
+        private static final Validator ADVANCED_SETTINGS_VALIDATOR = sBooleanValidator;
+
         /**
          * ADVANCED_SETTINGS default value.
          * @hide
@@ -1863,6 +1974,8 @@
         @Deprecated
         public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
 
+        private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = sBooleanValidator;
+
         /**
          * The static IP address.
          * <p>
@@ -1873,6 +1986,8 @@
         @Deprecated
         public static final String WIFI_STATIC_IP = "wifi_static_ip";
 
+        private static final Validator WIFI_STATIC_IP_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the gateway's IP address.
          * <p>
@@ -1883,6 +1998,8 @@
         @Deprecated
         public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
 
+        private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the net mask.
          * <p>
@@ -1893,6 +2010,8 @@
         @Deprecated
         public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
 
+        private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the primary DNS's IP address.
          * <p>
@@ -1903,6 +2022,8 @@
         @Deprecated
         public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
 
+        private static final Validator WIFI_STATIC_DNS1_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the secondary DNS's IP address.
          * <p>
@@ -1913,6 +2034,7 @@
         @Deprecated
         public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
 
+        private static final Validator WIFI_STATIC_DNS2_VALIDATOR = sLenientIpAddressValidator;
 
         /**
          * Determines whether remote devices may discover and/or connect to
@@ -1925,6 +2047,9 @@
         public static final String BLUETOOTH_DISCOVERABILITY =
             "bluetooth_discoverability";
 
+        private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 2);
+
         /**
          * Bluetooth discoverability timeout.  If this value is nonzero, then
          * Bluetooth becomes discoverable for a certain number of seconds,
@@ -1933,6 +2058,9 @@
         public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT =
             "bluetooth_discoverability_timeout";
 
+        private static final Validator BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR =
+                sNonNegativeIntegerValidator;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_ENABLED}
          * instead
@@ -1956,7 +2084,6 @@
         public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
             "lock_pattern_tactile_feedback_enabled";
 
-
         /**
          * A formatted string of the next alarm that is set, or the empty string
          * if there is no alarm set.
@@ -1966,11 +2093,31 @@
         @Deprecated
         public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
 
+        private static final Validator NEXT_ALARM_FORMATTED_VALIDATOR = new Validator() {
+            private static final int MAX_LENGTH = 1000;
+            @Override
+            public boolean validate(String value) {
+                // TODO: No idea what the correct format is.
+                return value == null || value.length() < MAX_LENGTH;
+            }
+        };
+
         /**
          * Scaling factor for fonts, float.
          */
         public static final String FONT_SCALE = "font_scale";
 
+        private static final Validator FONT_SCALE_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    return Float.parseFloat(value) >= 0;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        };
+
         /**
          * Name of an application package to be debugged.
          *
@@ -1995,6 +2142,8 @@
         @Deprecated
         public static final String DIM_SCREEN = "dim_screen";
 
+        private static final Validator DIM_SCREEN_VALIDATOR = sBooleanValidator;
+
         /**
          * The amount of time in milliseconds before the device goes to sleep or begins
          * to dream after a period of inactivity.  This value is also known as the
@@ -2003,16 +2152,23 @@
          */
         public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
+        private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR = sNonNegativeIntegerValidator;
+
         /**
          * The screen backlight brightness between 0 and 255.
          */
         public static final String SCREEN_BRIGHTNESS = "screen_brightness";
 
+        private static final Validator SCREEN_BRIGHTNESS_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 255);
+
         /**
          * Control whether to enable automatic brightness mode.
          */
         public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
 
+        private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = sBooleanValidator;
+
         /**
          * Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
          * or less (<0.0 >-1.0) bright.
@@ -2020,6 +2176,9 @@
          */
         public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
 
+        private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
+                new InclusiveFloatRangeValidator(-1, 1);
+
         /**
          * SCREEN_BRIGHTNESS_MODE value for manual mode.
          */
@@ -2055,12 +2214,18 @@
          */
         public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
 
-         /**
+        private static final Validator MODE_RINGER_STREAMS_AFFECTED_VALIDATOR =
+                sNonNegativeIntegerValidator;
+
+        /**
           * Determines which streams are affected by mute. The
           * stream type's bit should be set to 1 if it should be muted when a mute request
           * is received.
           */
-         public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+        public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+
+        private static final Validator MUTE_STREAMS_AFFECTED_VALIDATOR =
+                sNonNegativeIntegerValidator;
 
         /**
          * Whether vibrate is on for different events. This is used internally,
@@ -2068,6 +2233,8 @@
          */
         public static final String VIBRATE_ON = "vibrate_on";
 
+        private static final Validator VIBRATE_ON_VALIDATOR = sBooleanValidator;
+
         /**
          * If 1, redirects the system vibrator to all currently attached input devices
          * that support vibration.  If there are no such input devices, then the system
@@ -2082,54 +2249,72 @@
          */
         public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
 
+        private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = sBooleanValidator;
+
         /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
          */
         public static final String VOLUME_RING = "volume_ring";
 
+        private static final Validator VOLUME_RING_VALIDATOR = sVolumeValidator;
+
         /**
          * System/notifications volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
          */
         public static final String VOLUME_SYSTEM = "volume_system";
 
+        private static final Validator VOLUME_SYSTEM_VALIDATOR = sVolumeValidator;
+
         /**
          * Voice call volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
          */
         public static final String VOLUME_VOICE = "volume_voice";
 
+        private static final Validator VOLUME_VOICE_VALIDATOR = sVolumeValidator;
+
         /**
          * Music/media/gaming volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
          */
         public static final String VOLUME_MUSIC = "volume_music";
 
+        private static final Validator VOLUME_MUSIC_VALIDATOR = sVolumeValidator;
+
         /**
          * Alarm volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
          */
         public static final String VOLUME_ALARM = "volume_alarm";
 
+        private static final Validator VOLUME_ALARM_VALIDATOR = sVolumeValidator;
+
         /**
          * Notification volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
          */
         public static final String VOLUME_NOTIFICATION = "volume_notification";
 
+        private static final Validator VOLUME_NOTIFICATION_VALIDATOR = sVolumeValidator;
+
         /**
          * Bluetooth Headset volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
          */
         public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
 
+        private static final Validator VOLUME_BLUETOOTH_SCO_VALIDATOR = sVolumeValidator;
+
         /**
          * Master volume (float in the range 0.0f to 1.0f).
          * @hide
          */
         public static final String VOLUME_MASTER = "volume_master";
 
+        private static final Validator VOLUME_MASTER_VALIDATOR = sVolumeValidator;
+
         /**
          * Master volume mute (int 1 = mute, 0 = not muted).
          *
@@ -2137,6 +2322,8 @@
          */
         public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
 
+        private static final Validator VOLUME_MASTER_MUTE_VALIDATOR = sBooleanValidator;
+
         /**
          * Microphone mute (int 1 = mute, 0 = not muted).
          *
@@ -2144,6 +2331,8 @@
          */
         public static final String MICROPHONE_MUTE = "microphone_mute";
 
+        private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the notifications should use the ring volume (value of 1) or
          * a separate notification volume (value of 0). In most cases, users
@@ -2162,6 +2351,8 @@
         public static final String NOTIFICATIONS_USE_RING_VOLUME =
             "notifications_use_ring_volume";
 
+        private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether silent mode should allow vibration feedback. This is used
          * internally in AudioService and the Sound settings activity to
@@ -2176,6 +2367,8 @@
          */
         public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
 
+        private static final Validator VIBRATE_IN_SILENT_VALIDATOR = sBooleanValidator;
+
         /**
          * The mapping of stream type (integer) to its setting.
          */
@@ -2202,6 +2395,8 @@
          */
         public static final String RINGTONE = "ringtone";
 
+        private static final Validator RINGTONE_VALIDATOR = sUriValidator;
+
         /**
          * A {@link Uri} that will point to the current default ringtone at any
          * given time.
@@ -2220,6 +2415,8 @@
          */
         public static final String NOTIFICATION_SOUND = "notification_sound";
 
+        private static final Validator NOTIFICATION_SOUND_VALIDATOR = sUriValidator;
+
         /**
          * A {@link Uri} that will point to the current default notification
          * sound at any given time.
@@ -2236,6 +2433,8 @@
          */
         public static final String ALARM_ALERT = "alarm_alert";
 
+        private static final Validator ALARM_ALERT_VALIDATOR = sUriValidator;
+
         /**
          * A {@link Uri} that will point to the current default alarm alert at
          * any given time.
@@ -2251,30 +2450,52 @@
          */
         public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
 
+        private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    ComponentName.unflattenFromString(value);
+                    return true;
+                } catch (NullPointerException e) {
+                    return false;
+                }
+            }
+        };
+
         /**
          * Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_REPLACE = "auto_replace";
 
+        private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = sBooleanValidator;
+
         /**
          * Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_CAPS = "auto_caps";
 
+        private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
+
         /**
          * Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
          * feature converts two spaces to a "." and space.
          */
         public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
 
+        private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = sBooleanValidator;
+
         /**
          * Setting to showing password characters in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_SHOW_PASSWORD = "show_password";
 
+        private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = sBooleanValidator;
+
         public static final String SHOW_GTALK_SERVICE_STATUS =
                 "SHOW_GTALK_SERVICE_STATUS";
 
+        private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = sBooleanValidator;
+
         /**
          * Name of activity to use for wallpaper on the home screen.
          *
@@ -2283,6 +2504,18 @@
         @Deprecated
         public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
 
+        private static final Validator WALLPAPER_ACTIVITY_VALIDATOR = new Validator() {
+            private static final int MAX_LENGTH = 1000;
+
+            @Override
+            public boolean validate(String value) {
+                if (value != null && value.length() > MAX_LENGTH) {
+                    return false;
+                }
+                return ComponentName.unflattenFromString(value) != null;
+            }
+        };
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME}
          * instead
@@ -2304,6 +2537,10 @@
          */
         public static final String TIME_12_24 = "time_12_24";
 
+        /** @hide */
+        public static final Validator TIME_12_24_VALIDATOR =
+                new DiscreteValueValidator(new String[] {"12", "24"});
+
         /**
          * Date format string
          *   mm/dd/yyyy
@@ -2312,6 +2549,19 @@
          */
         public static final String DATE_FORMAT = "date_format";
 
+        /** @hide */
+        public static final Validator DATE_FORMAT_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    new SimpleDateFormat(value);
+                    return true;
+                } catch (IllegalArgumentException e) {
+                    return false;
+                }
+            }
+        };
+
         /**
          * Whether the setup wizard has been run before (on first boot), or if
          * it still needs to be run.
@@ -2321,6 +2571,9 @@
          */
         public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
 
+        /** @hide */
+        public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = sBooleanValidator;
+
         /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
@@ -2357,6 +2610,9 @@
          */
         public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
 
+        /** @hide */
+        public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = sBooleanValidator;
+
         /**
          * Default screen rotation when no other policy applies.
          * When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
@@ -2367,6 +2623,10 @@
          */
         public static final String USER_ROTATION = "user_rotation";
 
+        /** @hide */
+        public static final Validator USER_ROTATION_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 3);
+
         /**
          * Control whether the rotation lock toggle in the System UI should be hidden.
          * Typically this is done for accessibility purposes to make it harder for
@@ -2381,6 +2641,10 @@
         public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
                 "hide_rotation_lock_toggle_for_accessibility";
 
+        /** @hide */
+        public static final Validator HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR =
+                sBooleanValidator;
+
         /**
          * Whether the phone vibrates when it is ringing due to an incoming call. This will
          * be used by Phone and Setting apps; it shouldn't affect other apps.
@@ -2395,12 +2659,18 @@
          */
         public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
 
+        /** @hide */
+        public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the audible DTMF tones are played by the dialer when dialing. The value is
          * boolean (1 or 0).
          */
         public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
 
+        /** @hide */
+        public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
         /**
          * CDMA only settings
          * DTMF tone type played by the dialer when dialing.
@@ -2410,6 +2680,9 @@
          */
         public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
 
+        /** @hide */
+        public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the hearing aid is enabled. The value is
          * boolean (1 or 0).
@@ -2417,6 +2690,9 @@
          */
         public static final String HEARING_AID = "hearing_aid";
 
+        /** @hide */
+        public static final Validator HEARING_AID_VALIDATOR = sBooleanValidator;
+
         /**
          * CDMA only settings
          * TTY Mode
@@ -2428,18 +2704,27 @@
          */
         public static final String TTY_MODE = "tty_mode";
 
+        /** @hide */
+        public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
         /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
         public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
 
+        /** @hide */
+        public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the haptic feedback (long presses, ...) are enabled. The value is
          * boolean (1 or 0).
          */
         public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
 
+        /** @hide */
+        public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Each application that shows web suggestions should have its own
          * setting for this.
@@ -2447,6 +2732,9 @@
         @Deprecated
         public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
 
+        /** @hide */
+        public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the notification LED should repeatedly flash when a notification is
          * pending. The value is boolean (1 or 0).
@@ -2454,6 +2742,9 @@
          */
         public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
 
+        /** @hide */
+        public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = sBooleanValidator;
+
         /**
          * Show pointer location on screen?
          * 0 = no
@@ -2462,6 +2753,9 @@
          */
         public static final String POINTER_LOCATION = "pointer_location";
 
+        /** @hide */
+        public static final Validator POINTER_LOCATION_VALIDATOR = sBooleanValidator;
+
         /**
          * Show touch positions on screen?
          * 0 = no
@@ -2470,9 +2764,12 @@
          */
         public static final String SHOW_TOUCHES = "show_touches";
 
+        /** @hide */
+        public static final Validator SHOW_TOUCHES_VALIDATOR = sBooleanValidator;
+
         /**
          * Log raw orientation data from
-         * {@link com.android.internal.policy.impl.WindowOrientationListener} for use with the
+         * {@link com.android.server.policy.WindowOrientationListener} for use with the
          * orientationplot.py tool.
          * 0 = no
          * 1 = yes
@@ -2481,6 +2778,9 @@
         public static final String WINDOW_ORIENTATION_LISTENER_LOG =
                 "window_orientation_listener_log";
 
+        /** @hide */
+        public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
          * instead
@@ -2503,12 +2803,18 @@
          */
         public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
 
+        /** @hide */
+        public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the lockscreen should be completely disabled.
          * @hide
          */
         public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
 
+        /** @hide */
+        public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
          * instead
@@ -2573,6 +2879,9 @@
          */
         public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
 
+        /** @hide */
+        public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = sBooleanValidator;
+
         /**
          * Call Preference String.
          * "SIP_ALWAYS" : Always use SIP with network access
@@ -2581,18 +2890,28 @@
          */
         public static final String SIP_CALL_OPTIONS = "sip_call_options";
 
+        /** @hide */
+        public static final Validator SIP_CALL_OPTIONS_VALIDATOR = new DiscreteValueValidator(
+                new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
+
         /**
          * One of the sip call options: Always use SIP with network access.
          * @hide
          */
         public static final String SIP_ALWAYS = "SIP_ALWAYS";
 
+        /** @hide */
+        public static final Validator SIP_ALWAYS_VALIDATOR = sBooleanValidator;
+
         /**
          * One of the sip call options: Only if destination is a SIP address.
          * @hide
          */
         public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
 
+        /** @hide */
+        public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead.  Formerly used to indicate that
          * the user should be prompted each time a call is made whether it should be placed using
@@ -2603,6 +2922,9 @@
         @Deprecated
         public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
 
+        /** @hide */
+        public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = sBooleanValidator;
+
         /**
          * Pointer speed setting.
          * This is an integer value in a range between -7 and +7, so there are 15 possible values.
@@ -2613,12 +2935,19 @@
          */
         public static final String POINTER_SPEED = "pointer_speed";
 
+        /** @hide */
+        public static final Validator POINTER_SPEED_VALIDATOR =
+                new InclusiveFloatRangeValidator(-7, 7);
+
         /**
          * Whether lock-to-app will be triggered by long-press on recents.
          * @hide
          */
         public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
 
+        /** @hide */
+        public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * I am the lolrus.
          * <p>
@@ -2628,6 +2957,16 @@
          */
         public static final String EGG_MODE = "egg_mode";
 
+        /** @hide */
+        public static final Validator EGG_MODE_VALIDATOR = sBooleanValidator;
+
+        /**
+         * IMPORTANT: If you add a new public settings you also have to add it to
+         * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
+         * it to PRIVATE_SETTINGS below. Also add a validator that can validate
+         * the setting value. See an example above.
+         */
+
         /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
@@ -2698,17 +3037,207 @@
         };
 
         /**
-         * These entries are considered common between the personal and the managed profile,
-         * since the managed profile doesn't get to change them.
+         * These are all pulbic system settings
+         *
          * @hide
          */
-        public static final String[] CLONE_TO_MANAGED_PROFILE = {
-            DATE_FORMAT,
-            HAPTIC_FEEDBACK_ENABLED,
-            SOUND_EFFECTS_ENABLED,
-            TEXT_SHOW_PASSWORD,
-            TIME_12_24
-        };
+        public static final Set<String> PUBLIC_SETTINGS = new ArraySet<>();
+        static {
+            PUBLIC_SETTINGS.add(END_BUTTON_BEHAVIOR);
+            PUBLIC_SETTINGS.add(WIFI_USE_STATIC_IP);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_IP);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_GATEWAY);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_NETMASK);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_DNS1);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_DNS2);
+            PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY);
+            PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT);
+            PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED);
+            PUBLIC_SETTINGS.add(FONT_SCALE);
+            PUBLIC_SETTINGS.add(DIM_SCREEN);
+            PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT);
+            PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS);
+            PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE);
+            PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED);
+            PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED);
+            PUBLIC_SETTINGS.add(VIBRATE_ON);
+            PUBLIC_SETTINGS.add(VOLUME_RING);
+            PUBLIC_SETTINGS.add(VOLUME_SYSTEM);
+            PUBLIC_SETTINGS.add(VOLUME_VOICE);
+            PUBLIC_SETTINGS.add(VOLUME_MUSIC);
+            PUBLIC_SETTINGS.add(VOLUME_ALARM);
+            PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION);
+            PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
+            PUBLIC_SETTINGS.add(RINGTONE);
+            PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
+            PUBLIC_SETTINGS.add(ALARM_ALERT);
+            PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE);
+            PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS);
+            PUBLIC_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
+            PUBLIC_SETTINGS.add(TEXT_SHOW_PASSWORD);
+            PUBLIC_SETTINGS.add(SHOW_GTALK_SERVICE_STATUS);
+            PUBLIC_SETTINGS.add(WALLPAPER_ACTIVITY);
+            PUBLIC_SETTINGS.add(TIME_12_24);
+            PUBLIC_SETTINGS.add(DATE_FORMAT);
+            PUBLIC_SETTINGS.add(SETUP_WIZARD_HAS_RUN);
+            PUBLIC_SETTINGS.add(ACCELEROMETER_ROTATION);
+            PUBLIC_SETTINGS.add(USER_ROTATION);
+            PUBLIC_SETTINGS.add(DTMF_TONE_WHEN_DIALING);
+            PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
+            PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
+            PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+        }
+
+        /**
+         * These are all hidden system settings.
+         *
+         * @hide
+         */
+        public static final Set<String> PRIVATE_SETTINGS = new ArraySet<>();
+        static {
+            PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP);
+            PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
+            PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
+            PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
+            PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
+            PRIVATE_SETTINGS.add(VOLUME_MASTER);
+            PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
+            PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
+            PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
+            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);
+            PRIVATE_SETTINGS.add(NOTIFICATION_LIGHT_PULSE);
+            PRIVATE_SETTINGS.add(POINTER_LOCATION);
+            PRIVATE_SETTINGS.add(SHOW_TOUCHES);
+            PRIVATE_SETTINGS.add(WINDOW_ORIENTATION_LISTENER_LOG);
+            PRIVATE_SETTINGS.add(POWER_SOUNDS_ENABLED);
+            PRIVATE_SETTINGS.add(DOCK_SOUNDS_ENABLED);
+            PRIVATE_SETTINGS.add(LOCKSCREEN_SOUNDS_ENABLED);
+            PRIVATE_SETTINGS.add(LOCKSCREEN_DISABLED);
+            PRIVATE_SETTINGS.add(LOW_BATTERY_SOUND);
+            PRIVATE_SETTINGS.add(DESK_DOCK_SOUND);
+            PRIVATE_SETTINGS.add(DESK_UNDOCK_SOUND);
+            PRIVATE_SETTINGS.add(CAR_DOCK_SOUND);
+            PRIVATE_SETTINGS.add(CAR_UNDOCK_SOUND);
+            PRIVATE_SETTINGS.add(LOCK_SOUND);
+            PRIVATE_SETTINGS.add(UNLOCK_SOUND);
+            PRIVATE_SETTINGS.add(SIP_RECEIVE_CALLS);
+            PRIVATE_SETTINGS.add(SIP_CALL_OPTIONS);
+            PRIVATE_SETTINGS.add(SIP_ALWAYS);
+            PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY);
+            PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
+            PRIVATE_SETTINGS.add(POINTER_SPEED);
+            PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
+            PRIVATE_SETTINGS.add(EGG_MODE);
+        }
+
+        /**
+         * These are all pulbic system settings
+         *
+         * @hide
+         */
+        public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+        static {
+            VALIDATORS.put(END_BUTTON_BEHAVIOR,END_BUTTON_BEHAVIOR_VALIDATOR);
+            VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+            VALIDATORS.put(BLUETOOTH_DISCOVERABILITY, BLUETOOTH_DISCOVERABILITY_VALIDATOR);
+            VALIDATORS.put(BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+                    BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR);
+            VALIDATORS.put(NEXT_ALARM_FORMATTED, NEXT_ALARM_FORMATTED_VALIDATOR);
+            VALIDATORS.put(FONT_SCALE, FONT_SCALE_VALIDATOR);
+            VALIDATORS.put(DIM_SCREEN, DIM_SCREEN_VALIDATOR);
+            VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
+            VALIDATORS.put(SCREEN_BRIGHTNESS, SCREEN_BRIGHTNESS_VALIDATOR);
+            VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
+            VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
+            VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
+            VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
+            VALIDATORS.put(VOLUME_RING, VOLUME_RING_VALIDATOR);
+            VALIDATORS.put(VOLUME_SYSTEM, VOLUME_SYSTEM_VALIDATOR);
+            VALIDATORS.put(VOLUME_VOICE, VOLUME_VOICE_VALIDATOR);
+            VALIDATORS.put(VOLUME_MUSIC, VOLUME_MUSIC_VALIDATOR);
+            VALIDATORS.put(VOLUME_ALARM, VOLUME_ALARM_VALIDATOR);
+            VALIDATORS.put(VOLUME_NOTIFICATION, VOLUME_NOTIFICATION_VALIDATOR);
+            VALIDATORS.put(VOLUME_BLUETOOTH_SCO, VOLUME_BLUETOOTH_SCO_VALIDATOR);
+            VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
+            VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
+            VALIDATORS.put(TEXT_AUTO_REPLACE, TEXT_AUTO_REPLACE_VALIDATOR);
+            VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
+            VALIDATORS.put(TEXT_AUTO_PUNCTUATE, TEXT_AUTO_PUNCTUATE_VALIDATOR);
+            VALIDATORS.put(TEXT_SHOW_PASSWORD, TEXT_SHOW_PASSWORD_VALIDATOR);
+            VALIDATORS.put(SHOW_GTALK_SERVICE_STATUS, SHOW_GTALK_SERVICE_STATUS_VALIDATOR);
+            VALIDATORS.put(WALLPAPER_ACTIVITY, WALLPAPER_ACTIVITY_VALIDATOR);
+            VALIDATORS.put(TIME_12_24, TIME_12_24_VALIDATOR);
+            VALIDATORS.put(DATE_FORMAT, DATE_FORMAT_VALIDATOR);
+            VALIDATORS.put(SETUP_WIZARD_HAS_RUN, SETUP_WIZARD_HAS_RUN_VALIDATOR);
+            VALIDATORS.put(ACCELEROMETER_ROTATION, ACCELEROMETER_ROTATION_VALIDATOR);
+            VALIDATORS.put(USER_ROTATION, USER_ROTATION_VALIDATOR);
+            VALIDATORS.put(DTMF_TONE_WHEN_DIALING, DTMF_TONE_WHEN_DIALING_VALIDATOR);
+            VALIDATORS.put(SOUND_EFFECTS_ENABLED, SOUND_EFFECTS_ENABLED_VALIDATOR);
+            VALIDATORS.put(HAPTIC_FEEDBACK_ENABLED, HAPTIC_FEEDBACK_ENABLED_VALIDATOR);
+            VALIDATORS.put(SHOW_WEB_SUGGESTIONS, SHOW_WEB_SUGGESTIONS_VALIDATOR);
+            VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+            VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
+            VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
+            VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
+            VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
+            VALIDATORS.put(VOLUME_MASTER, VOLUME_MASTER_VALIDATOR);
+            VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
+            VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
+            VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
+            VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
+            VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
+            VALIDATORS.put(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
+                    HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR);
+            VALIDATORS.put(VIBRATE_WHEN_RINGING, VIBRATE_WHEN_RINGING_VALIDATOR);
+            VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
+            VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
+            VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
+            VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
+            VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
+            VALIDATORS.put(WINDOW_ORIENTATION_LISTENER_LOG,
+                    WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR);
+            VALIDATORS.put(LOCKSCREEN_SOUNDS_ENABLED, LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR);
+            VALIDATORS.put(LOCKSCREEN_DISABLED, LOCKSCREEN_DISABLED_VALIDATOR);
+            VALIDATORS.put(SIP_RECEIVE_CALLS, SIP_RECEIVE_CALLS_VALIDATOR);
+            VALIDATORS.put(SIP_CALL_OPTIONS, SIP_CALL_OPTIONS_VALIDATOR);
+            VALIDATORS.put(SIP_ALWAYS, SIP_ALWAYS_VALIDATOR);
+            VALIDATORS.put(SIP_ADDRESS_ONLY, SIP_ADDRESS_ONLY_VALIDATOR);
+            VALIDATORS.put(SIP_ASK_ME_EACH_TIME, SIP_ASK_ME_EACH_TIME_VALIDATOR);
+            VALIDATORS.put(POINTER_SPEED, POINTER_SPEED_VALIDATOR);
+            VALIDATORS.put(LOCK_TO_APP_ENABLED, LOCK_TO_APP_ENABLED_VALIDATOR);
+            VALIDATORS.put(EGG_MODE, EGG_MODE_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_IP, WIFI_STATIC_IP_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_GATEWAY, WIFI_STATIC_GATEWAY_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
+        }
+
+        /**
+         * These entries are considered common between the personal and the managed profile,
+         * since the managed profile doesn't get to change them.
+         */
+        private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+        static {
+            CLONE_TO_MANAGED_PROFILE.add(DATE_FORMAT);
+            CLONE_TO_MANAGED_PROFILE.add(HAPTIC_FEEDBACK_ENABLED);
+            CLONE_TO_MANAGED_PROFILE.add(SOUND_EFFECTS_ENABLED);
+            CLONE_TO_MANAGED_PROFILE.add(TEXT_SHOW_PASSWORD);
+            CLONE_TO_MANAGED_PROFILE.add(TIME_12_24);
+        }
+
+        /** @hide */
+        public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+            outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+        }
 
         /**
          * When to use Wi-Fi calling
@@ -3098,7 +3627,7 @@
         }
 
         /** @hide */
-        public static void getMovedKeys(HashSet<String> outKeySet) {
+        public static void getMovedToGlobalSettings(Set<String> outKeySet) {
             outKeySet.addAll(MOVED_TO_GLOBAL);
         }
 
@@ -4895,22 +5424,27 @@
         /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
-         * @hide
          */
-        public static final String[] CLONE_TO_MANAGED_PROFILE = {
-            ACCESSIBILITY_ENABLED,
-            ALLOW_MOCK_LOCATION,
-            ALLOWED_GEOLOCATION_ORIGINS,
-            DEFAULT_INPUT_METHOD,
-            ENABLED_ACCESSIBILITY_SERVICES,
-            ENABLED_INPUT_METHODS,
-            LOCATION_MODE,
-            LOCATION_PROVIDERS_ALLOWED,
-            LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
-            SELECTED_INPUT_METHOD_SUBTYPE,
-            SELECTED_SPELL_CHECKER,
-            SELECTED_SPELL_CHECKER_SUBTYPE
-        };
+        private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+        static {
+            CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
+            CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
+            CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS);
+            CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
+            CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
+            CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+            CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
+            CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
+            CLONE_TO_MANAGED_PROFILE.add(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+            CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
+            CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
+            CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
+        }
+
+        /** @hide */
+        public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+            outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+        }
 
         /**
          * Helper method for determining if a location provider is enabled.
@@ -5104,6 +5638,7 @@
          * Whether Theater Mode is on.
          * {@hide}
          */
+        @SystemApi
         public static final String THEATER_MODE_ON = "theater_mode_on";
 
         /**
@@ -6543,7 +7078,7 @@
         /**
          * Defines global runtime overrides to window policy.
          *
-         * See {@link com.android.internal.policy.impl.PolicyControl} for value format.
+         * See {@link com.android.server.policy.PolicyControl} for value format.
          *
          * @hide
          */
@@ -6691,6 +7226,11 @@
             MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
         }
 
+        /** @hide */
+        public static void getMovedToSecureSettings(Set<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_SECURE);
+        }
+
         /**
          * Look up a name in the database.
          * @param resolver to access the database with
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 38b043971..fa5ac42 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -18,6 +18,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.AlarmManager;
@@ -37,6 +38,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -46,7 +48,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.util.MathUtils;
 
-import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.DumpUtils.Dump;
 
@@ -442,6 +443,7 @@
      *
      * @return The view if found or null otherwise.
      */
+    @Nullable
     public View findViewById(int id) {
         return getWindow().findViewById(id);
     }
@@ -945,7 +947,7 @@
             throw new IllegalStateException("Only doze dreams can be windowless");
         }
         if (!mWindowless) {
-            mWindow = PolicyManager.makeNewWindow(this);
+            mWindow = new PhoneWindow(this);
             mWindow.setCallback(this);
             mWindow.requestFeature(Window.FEATURE_NO_TITLE);
             mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 2b53c48..b84c3aa 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1754,8 +1754,8 @@
 
     private char getEllipsisChar(TextUtils.TruncateAt method) {
         return (method == TextUtils.TruncateAt.END_SMALL) ?
-                ELLIPSIS_TWO_DOTS[0] :
-                ELLIPSIS_NORMAL[0];
+                TextUtils.ELLIPSIS_TWO_DOTS[0] :
+                TextUtils.ELLIPSIS_NORMAL[0];
     }
 
     private void ellipsize(int start, int end, int line,
@@ -1952,6 +1952,4 @@
     /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT =
         new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
 
-    /* package */ static final char[] ELLIPSIS_NORMAL = { '\u2026' }; // this is "..."
-    /* package */ static final char[] ELLIPSIS_TWO_DOTS = { '\u2025' }; // this is ".."
 }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 5b07397..2d4b4dc 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -554,7 +554,7 @@
 
         float ellipsisWidth = paint.measureText(
                 (where == TextUtils.TruncateAt.END_SMALL) ?
-                        ELLIPSIS_TWO_DOTS : ELLIPSIS_NORMAL, 0, 1);
+                        TextUtils.ELLIPSIS_TWO_DOTS : TextUtils.ELLIPSIS_NORMAL, 0, 1);
         int ellipsisStart = 0;
         int ellipsisCount = 0;
         int len = lineEnd - lineStart;
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 8a8c6d8..48bb5dd 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -63,9 +63,12 @@
 
 public class TextUtils {
     private static final String TAG = "TextUtils";
-    private static final String ELLIPSIS = new String(Layout.ELLIPSIS_NORMAL);
-    private static final String ELLIPSIS_TWO_DOTS = new String(Layout.ELLIPSIS_TWO_DOTS);
 
+    /* package */ static final char[] ELLIPSIS_NORMAL = { '\u2026' }; // this is "..."
+    private static final String ELLIPSIS_STRING = new String(ELLIPSIS_NORMAL);
+
+    /* package */ static final char[] ELLIPSIS_TWO_DOTS = { '\u2025' }; // this is ".."
+    private static final String ELLIPSIS_TWO_DOTS_STRING = new String(ELLIPSIS_TWO_DOTS);
 
     private TextUtils() { /* cannot be instantiated */ }
 
@@ -1085,7 +1088,7 @@
                                          EllipsizeCallback callback) {
         return ellipsize(text, paint, avail, where, preserveLength, callback,
                 TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                (where == TruncateAt.END_SMALL) ? ELLIPSIS_TWO_DOTS : ELLIPSIS);
+                (where == TruncateAt.END_SMALL) ? ELLIPSIS_TWO_DOTS_STRING : ELLIPSIS_STRING);
     }
 
     /**
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index d0ed871..ac98e8a 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -28,9 +28,11 @@
 import java.util.Formatter;
 import java.util.GregorianCalendar;
 import java.util.Locale;
+import java.util.TimeZone;
 
 import libcore.icu.DateIntervalFormat;
 import libcore.icu.LocaleData;
+import libcore.icu.RelativeDateTimeFormatter;
 
 /**
  * This class contains various date-related utilities for creating text for things like
@@ -242,6 +244,8 @@
 
     /**
      * Returns a string describing the elapsed time since startTime.
+     * <p>
+     * The minimum timespan to report is set to {@link #MINUTE_IN_MILLIS}.
      * @param startTime some time in the past.
      * @return a String object containing the elapsed time.
      * @see #getRelativeTimeSpanString(long, long, long)
@@ -289,69 +293,8 @@
      */
     public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution,
             int flags) {
-        Resources r = Resources.getSystem();
-        boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;
-
-        boolean past = (now >= time);
-        long duration = Math.abs(now - time);
-
-        int resId;
-        long count;
-        if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
-            count = duration / SECOND_IN_MILLIS;
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_seconds_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_seconds_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_seconds;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_seconds;
-                }
-            }
-        } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
-            count = duration / MINUTE_IN_MILLIS;
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_minutes_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_minutes_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_minutes;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_minutes;
-                }
-            }
-        } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
-            count = duration / HOUR_IN_MILLIS;
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_hours_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_hours_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_hours;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_hours;
-                }
-            }
-        } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
-            return getRelativeDayString(r, time, now);
-        } else {
-            // We know that we won't be showing the time, so it is safe to pass
-            // in a null context.
-            return formatDateRange(null, time, time, flags);
-        }
-
-        String format = r.getQuantityString(resId, (int) count);
-        return String.format(format, count);
+        return RelativeDateTimeFormatter.getRelativeTimeSpanString(Locale.getDefault(),
+                TimeZone.getDefault(), time, now, minResolution, flags);
     }
 
     /**
@@ -360,8 +303,8 @@
      * <p>
      * Example output strings for the US date format.
      * <ul>
-     * <li>3 mins ago, 10:15 AM</li>
-     * <li>yesterday, 12:20 PM</li>
+     * <li>3 min. ago, 10:15 AM</li>
+     * <li>Yesterday, 12:20 PM</li>
      * <li>Dec 12, 4:12 AM</li>
      * <li>11/14/2007, 8:20 AM</li>
      * </ul>
@@ -374,86 +317,19 @@
      * @param transitionResolution the elapsed time (in milliseconds) at which
      *            to stop reporting relative measurements. Elapsed times greater
      *            than this resolution will default to normal date formatting.
-     *            For example, will transition from "6 days ago" to "Dec 12"
+     *            For example, will transition from "7 days ago" to "Dec 12"
      *            when using {@link #WEEK_IN_MILLIS}.
      */
     public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
             long transitionResolution, int flags) {
-        Resources r = Resources.getSystem();
-
-        long now = System.currentTimeMillis();
-        long duration = Math.abs(now - time);
-
-        // getRelativeTimeSpanString() doesn't correctly format relative dates
-        // above a week or exact dates below a day, so clamp
-        // transitionResolution as needed.
-        if (transitionResolution > WEEK_IN_MILLIS) {
-            transitionResolution = WEEK_IN_MILLIS;
-        } else if (transitionResolution < DAY_IN_MILLIS) {
-            transitionResolution = DAY_IN_MILLIS;
+        // Same reason as in formatDateRange() to explicitly indicate 12- or 24-hour format.
+        if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) {
+            flags |= DateFormat.is24HourFormat(c) ? FORMAT_24HOUR : FORMAT_12HOUR;
         }
 
-        CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME);
-
-        String result;
-        if (duration < transitionResolution) {
-            CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags);
-            result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause);
-        } else {
-            CharSequence dateClause = getRelativeTimeSpanString(c, time, false);
-            result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause);
-        }
-
-        return result;
-    }
-
-    /**
-     * Returns a string describing a day relative to the current day. For example if the day is
-     * today this function returns "Today", if the day was a week ago it returns "7 days ago", and
-     * if the day is in 2 weeks it returns "in 14 days".
-     *
-     * @param r the resources
-     * @param day the relative day to describe in UTC milliseconds
-     * @param today the current time in UTC milliseconds
-     */
-    private static final String getRelativeDayString(Resources r, long day, long today) {
-        Locale locale = r.getConfiguration().locale;
-        if (locale == null) {
-            locale = Locale.getDefault();
-        }
-
-        // TODO: use TimeZone.getOffset instead.
-        Time startTime = new Time();
-        startTime.set(day);
-        int startDay = Time.getJulianDay(day, startTime.gmtoff);
-
-        Time currentTime = new Time();
-        currentTime.set(today);
-        int currentDay = Time.getJulianDay(today, currentTime.gmtoff);
-
-        int days = Math.abs(currentDay - startDay);
-        boolean past = (today > day);
-
-        // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
-        if (days == 1) {
-            if (past) {
-                return LocaleData.get(locale).yesterday;
-            } else {
-                return LocaleData.get(locale).tomorrow;
-            }
-        } else if (days == 0) {
-            return LocaleData.get(locale).today;
-        }
-
-        int resId;
-        if (past) {
-            resId = com.android.internal.R.plurals.num_days_ago;
-        } else {
-            resId = com.android.internal.R.plurals.in_num_days;
-        }
-
-        String format = r.getQuantityString(resId, days);
-        return String.format(format, days);
+        return RelativeDateTimeFormatter.getRelativeDateTimeString(Locale.getDefault(),
+                TimeZone.getDefault(), time, System.currentTimeMillis(), minResolution,
+                transitionResolution, flags);
     }
 
     private static void initFormatStrings() {
diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java
index f95fb49..70dfe7f 100644
--- a/core/java/android/transition/ArcMotion.java
+++ b/core/java/android/transition/ArcMotion.java
@@ -21,7 +21,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Path;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 
 /**
  * A PathMotion that generates a curved path along an arc on an imaginary circle containing
@@ -257,7 +256,7 @@
             }
             if (newArcDistance2 != 0) {
                 float ratio2 = newArcDistance2 / arcDist2;
-                float ratio = FloatMath.sqrt(ratio2);
+                float ratio = (float) Math.sqrt(ratio2);
                 ex = dx + (ratio * (ex - dx));
                 ey = dy + (ratio * (ey - dy));
             }
diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java
index 51beb51..1e44cfa 100644
--- a/core/java/android/transition/CircularPropagation.java
+++ b/core/java/android/transition/CircularPropagation.java
@@ -16,7 +16,6 @@
 package android.transition;
 
 import android.graphics.Rect;
-import android.util.FloatMath;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -87,9 +86,9 @@
             epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2)
                     + sceneRoot.getTranslationY());
         }
-        float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
-        float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
-        float distanceFraction = distance/maxDistance;
+        double distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
+        double maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
+        double distanceFraction = distance/maxDistance;
 
         long duration = transition.getDuration();
         if (duration < 0) {
@@ -99,9 +98,9 @@
         return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
     }
 
-    private static float distance(float x1, float y1, float x2, float y2) {
-        float x = x2 - x1;
-        float y = y2 - y1;
-        return FloatMath.sqrt((x * x) + (y * y));
+    private static double distance(float x1, float y1, float x2, float y2) {
+        double x = x2 - x1;
+        double y = y2 - y1;
+        return Math.hypot(x, y);
     }
 }
diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java
index 0ccdf15..788676a 100644
--- a/core/java/android/transition/Explode.java
+++ b/core/java/android/transition/Explode.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
@@ -143,32 +142,29 @@
 
         int centerX = bounds.centerX();
         int centerY = bounds.centerY();
-        float xVector = centerX - focalX;
-        float yVector = centerY - focalY;
+        double xVector = centerX - focalX;
+        double yVector = centerY - focalY;
 
         if (xVector == 0 && yVector == 0) {
             // Random direction when View is centered on focal View.
-            xVector = (float) (Math.random() * 2) - 1;
-            yVector = (float) (Math.random() * 2) - 1;
+            xVector = (Math.random() * 2) - 1;
+            yVector = (Math.random() * 2) - 1;
         }
-        float vectorSize = calculateDistance(xVector, yVector);
+        double vectorSize = Math.hypot(xVector, yVector);
         xVector /= vectorSize;
         yVector /= vectorSize;
 
-        float maxDistance =
+        double maxDistance =
                 calculateMaxDistance(sceneRoot, focalX - sceneRootX, focalY - sceneRootY);
 
-        outVector[0] = Math.round(maxDistance * xVector);
-        outVector[1] = Math.round(maxDistance * yVector);
+        outVector[0] = (int) Math.round(maxDistance * xVector);
+        outVector[1] = (int) Math.round(maxDistance * yVector);
     }
 
-    private static float calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
+    private static double calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
         int maxX = Math.max(focalX, sceneRoot.getWidth() - focalX);
         int maxY = Math.max(focalY, sceneRoot.getHeight() - focalY);
-        return calculateDistance(maxX, maxY);
+        return Math.hypot(maxX, maxY);
     }
 
-    private static float calculateDistance(float x, float y) {
-        return FloatMath.sqrt((x * x) + (y * y));
-    }
 }
diff --git a/core/java/android/transition/PatternPathMotion.java b/core/java/android/transition/PatternPathMotion.java
index a609df6..773c387 100644
--- a/core/java/android/transition/PatternPathMotion.java
+++ b/core/java/android/transition/PatternPathMotion.java
@@ -23,7 +23,6 @@
 import android.graphics.Path;
 import android.graphics.PathMeasure;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.util.PathParser;
 
 /**
@@ -119,7 +118,7 @@
         mTempMatrix.setTranslate(-startX, -startY);
         float dx = endX - startX;
         float dy = endY - startY;
-        float distance = distance(dx, dy);
+        float distance = (float) Math.hypot(dx, dy);
         float scale = 1 / distance;
         mTempMatrix.postScale(scale, scale);
         double angle = Math.atan2(dy, dx);
@@ -130,9 +129,9 @@
 
     @Override
     public Path getPath(float startX, float startY, float endX, float endY) {
-        float dx = endX - startX;
-        float dy = endY - startY;
-        float length = distance(dx, dy);
+        double dx = endX - startX;
+        double dy = endY - startY;
+        float length = (float) Math.hypot(dx, dy);
         double angle = Math.atan2(dy, dx);
 
         mTempMatrix.setScale(length, length);
@@ -143,7 +142,4 @@
         return path;
     }
 
-    private static float distance(float x, float y) {
-        return FloatMath.sqrt((x * x) + (y * y));
-    }
 }
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index ad6c2dd..5dd1fff 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -16,7 +16,6 @@
 package android.transition;
 
 import android.graphics.Rect;
-import android.util.FloatMath;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 7bd6287..80245ef 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -268,7 +268,12 @@
         @Override
         public boolean onPreDraw() {
             removeListeners();
-            sPendingTransitions.remove(mSceneRoot);
+
+            // Don't start the transition if it's no longer pending.
+            if (!sPendingTransitions.remove(mSceneRoot)) {
+                return true;
+            }
+
             // Add to running list, handle end to remove it
             final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
                     getRunningTransitions();
@@ -417,4 +422,24 @@
             sceneChangeRunTransition(sceneRoot, transitionClone);
         }
     }
+
+    /**
+     * Ends all pending and ongoing transitions on the specified scene root.
+     *
+     * @param sceneRoot The root of the View hierarchy to end transitions on.
+     * @hide
+     */
+    public static void endTransitions(final ViewGroup sceneRoot) {
+        sPendingTransitions.remove(sceneRoot);
+
+        final ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
+        if (runningTransitions != null) {
+            final int count = runningTransitions.size();
+            for (int i = 0; i < count; i++) {
+                final Transition transition = runningTransitions.get(i);
+                transition.end();
+            }
+        }
+
+    }
 }
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 7c9861f..6ed3885 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -255,7 +255,10 @@
     }
 
     private ArrayMap(boolean immutable) {
-        mHashes = EmptyArray.INT;
+        // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
+        // instance instead of the usual EmptyArray.INT. The reference
+        // is checked later to see if the array is allowed to grow.
+        mHashes = immutable ? EMPTY_IMMUTABLE_INTS : EmptyArray.INT;
         mArray = EmptyArray.OBJECT;
         mSize = 0;
     }
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index a6466fc..3aa3447 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -102,7 +102,7 @@
             str = new FileOutputStream(mBaseName);
         } catch (FileNotFoundException e) {
             File parent = mBaseName.getParentFile();
-            if (!parent.mkdir()) {
+            if (!parent.mkdirs()) {
                 throw new IOException("Couldn't create directory " + mBaseName);
             }
             FileUtils.setPermissions(
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index c855e57..d0e5b9e 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -62,6 +62,13 @@
     public static final int DENSITY_HIGH = 240;
 
     /**
+     * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+     * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+     * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+     */
+    public static final int DENSITY_280 = 280;
+
+    /**
      * Standard quantized DPI for extra-high-density screens.
      */
     public static final int DENSITY_XHIGH = 320;
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 5e05683..68ad782 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -636,95 +636,6 @@
         }
     }
 
-    public void computeClickPointInScreenClientThread(long accessibilityNodeId,
-            Region interactiveRegion, int interactionId,
-            IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
-            long interrogatingTid, MagnificationSpec spec) {
-        Message message = mHandler.obtainMessage();
-        message.what = PrivateHandler.MSG_COMPUTE_CLICK_POINT_IN_SCREEN;
-
-        SomeArgs args = SomeArgs.obtain();
-        args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
-        args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
-        args.argi3 = interactionId;
-        args.arg1 = callback;
-        args.arg2 = spec;
-        args.arg3 = interactiveRegion;
-
-        message.obj = args;
-
-        // If the interrogation is performed by the same thread as the main UI
-        // thread in this process, set the message as a static reference so
-        // after this call completes the same thread but in the interrogating
-        // client can handle the message to generate the result.
-        if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
-            AccessibilityInteractionClient.getInstanceForThread(
-                    interrogatingTid).setSameThreadMessage(message);
-        } else {
-            mHandler.sendMessage(message);
-        }
-    }
-
-    private void computeClickPointInScreenUiThread(Message message) {
-        SomeArgs args = (SomeArgs) message.obj;
-        final int accessibilityViewId = args.argi1;
-        final int virtualDescendantId = args.argi2;
-        final int interactionId = args.argi3;
-        final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) args.arg1;
-        final MagnificationSpec spec = (MagnificationSpec) args.arg2;
-        final Region interactiveRegion = (Region) args.arg3;
-        args.recycle();
-
-        boolean succeeded = false;
-        Point point = mTempPoint;
-        try {
-            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
-                return;
-            }
-            View target = null;
-            if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                target = findViewByAccessibilityId(accessibilityViewId);
-            } else {
-                target = mViewRootImpl.mView;
-            }
-            if (target != null && isShown(target)) {
-                AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
-                if (provider != null) {
-                    // For virtual views just use the center of the bounds in screen.
-                    AccessibilityNodeInfo node = null;
-                    if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                        node = provider.createAccessibilityNodeInfo(virtualDescendantId);
-                    } else {
-                        node = provider.createAccessibilityNodeInfo(
-                                AccessibilityNodeProvider.HOST_VIEW_ID);
-                    }
-                    if (node != null) {
-                        succeeded = true;
-                        Rect boundsInScreen = mTempRect;
-                        node.getBoundsInScreen(boundsInScreen);
-                        point.set(boundsInScreen.centerX(), boundsInScreen.centerY());
-                    }
-                } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                    // For a real view, ask the view to compute the click point.
-                    succeeded = target.computeClickPointInScreenForAccessibility(
-                            interactiveRegion, point);
-                }
-            }
-        } finally {
-            try {
-                Point result = null;
-                if (succeeded) {
-                    applyAppScaleAndMagnificationSpecIfNeeded(point, spec);
-                    result = point;
-                }
-                callback.setComputeClickPointInScreenActionResult(result, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - the other side will time out */
-            }
-        }
-    }
-
     private View findViewByAccessibilityId(int accessibilityId) {
         View root = mViewRootImpl.mView;
         if (root == null) {
@@ -1201,7 +1112,6 @@
         private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
         private final static int MSG_FIND_FOCUS = 5;
         private final static int MSG_FOCUS_SEARCH = 6;
-        private final static int MSG_COMPUTE_CLICK_POINT_IN_SCREEN = 7;
 
         public PrivateHandler(Looper looper) {
             super(looper);
@@ -1223,8 +1133,6 @@
                     return "MSG_FIND_FOCUS";
                 case MSG_FOCUS_SEARCH:
                     return "MSG_FOCUS_SEARCH";
-                case MSG_COMPUTE_CLICK_POINT_IN_SCREEN:
-                    return "MSG_COMPUTE_CLICK_POINT_IN_SCREEN";
                 default:
                     throw new IllegalArgumentException("Unknown message type: " + type);
             }
@@ -1252,9 +1160,6 @@
                 case MSG_FOCUS_SEARCH: {
                     focusSearchUiThread(message);
                 } break;
-                case MSG_COMPUTE_CLICK_POINT_IN_SCREEN: {
-                    computeClickPointInScreenUiThread(message);
-                } break;
                 default:
                     throw new IllegalArgumentException("Unknown message type: " + type);
             }
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index a359952..ae4b60f 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -29,8 +29,21 @@
  * </div>
  */
 public abstract class ActionMode {
+
+    /**
+     * The action mode is treated as a Primary mode. This is the default.
+     * Use with {@link #setType}.
+     */
+    public static final int TYPE_PRIMARY = 0;
+    /**
+     * The action mode is treated as a Floating Toolbar.
+     * Use with {@link #setType}.
+     */
+    public static final int TYPE_FLOATING = 1;
+
     private Object mTag;
     private boolean mTitleOptionalHint;
+    private int mType = TYPE_PRIMARY;
 
     /**
      * Set a tag object associated with this ActionMode.
@@ -154,6 +167,25 @@
     public abstract void setCustomView(View view);
 
     /**
+     * Set a type for this action mode. This will affect how the system renders the action mode if
+     * it has to.
+     *
+     * @param type One of {@link #TYPE_PRIMARY} or {@link #TYPE_FLOATING}.
+     */
+    public void setType(int type) {
+        mType = type;
+    }
+
+    /**
+     * Returns the type for this action mode.
+     *
+     * @return One of {@link #TYPE_PRIMARY} or {@link #TYPE_FLOATING}.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
      * Invalidate the action mode and refresh menu content. The mode's
      * {@link ActionMode.Callback} will have its
      * {@link Callback#onPrepareActionMode(ActionMode, Menu)} method called.
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ac32430..a5225cb 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -16,24 +16,25 @@
 
 package android.view;
 
-import android.annotation.Nullable;
-import android.graphics.Canvas;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Trace;
-import android.util.TypedValue;
-import android.widget.FrameLayout;
+import com.android.internal.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.Canvas;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.util.Xml;
+import android.widget.FrameLayout;
 
 import java.io.IOException;
 import java.lang.reflect.Constructor;
@@ -925,6 +926,14 @@
                                 inheritContext);
                         final ViewGroup group = (ViewGroup) parent;
 
+                        final TypedArray a = context.obtainStyledAttributes(
+                                attrs, R.styleable.Include);
+                        final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                        final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                        final boolean hasWidth = a.hasValue(R.styleable.Include_layout_width);
+                        final boolean hasHeight = a.hasValue(R.styleable.Include_layout_height);
+                        a.recycle();
+
                         // We try to load the layout params set in the <include /> tag. If
                         // they don't exist, we will rely on the layout params set in the
                         // included XML file.
@@ -934,27 +943,21 @@
                         // successfully loaded layout params from the <include /> tag,
                         // false means we need to rely on the included layout params.
                         ViewGroup.LayoutParams params = null;
-                        try {
-                            params = group.generateLayoutParams(attrs);
-                        } catch (RuntimeException e) {
-                            params = group.generateLayoutParams(childAttrs);
-                        } finally {
-                            if (params != null) {
-                                view.setLayoutParams(params);
+                        if (hasWidth && hasHeight) {
+                            try {
+                                params = group.generateLayoutParams(attrs);
+                            } catch (RuntimeException e) {
+                                // Ignore, just fail over to child attrs.
                             }
                         }
+                        if (params == null) {
+                            params = group.generateLayoutParams(childAttrs);
+                        }
+                        view.setLayoutParams(params);
 
                         // Inflate all children.
                         rInflate(childParser, view, childAttrs, true, true);
 
-                        final TypedArray a = context.obtainStyledAttributes(
-                                attrs, com.android.internal.R.styleable.Include);
-                        final int id = a.getResourceId(
-                                com.android.internal.R.styleable.Include_id, View.NO_ID);
-                        final int visibility = a.getInt(
-                                com.android.internal.R.styleable.Include_visibility, -1);
-                        a.recycle();
-
                         if (id != View.NO_ID) {
                             view.setId(id);
                         }
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 1c5c41c..5e45c8f 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -402,6 +402,23 @@
     public static final int FLAG_TAINTED = 0x80000000;
 
     /**
+     * Private flag indicating that this event was synthesized by the system and
+     * should be delivered to the accessibility focused view first. When being
+     * dispatched such an event is not handled by predecessors of the accessibility
+     * focused view and after the event reaches that view the flag is cleared and
+     * normal event dispatch is performed. This ensures that the platform can click
+     * on any view that has accessibility focus which is semantically equivalent to
+     * asking the view to perform a click accessibility action but more generic as
+     * views not implementing click action correctly can still be activated.
+     *
+     * @hide
+     * @see #isTargetAccessibilityFocus()
+     * @see #setTargetAccessibilityFocus(boolean)
+     */
+    public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000;
+
+
+    /**
      * Flag indicating the motion event intersected the top edge of the screen.
      */
     public static final int EDGE_TOP = 0x00000001;
@@ -1766,6 +1783,20 @@
         nativeSetFlags(mNativePtr, tainted ? flags | FLAG_TAINTED : flags & ~FLAG_TAINTED);
     }
 
+    /** @hide */
+    public final boolean isTargetAccessibilityFocus() {
+        final int flags = getFlags();
+        return (flags & FLAG_TARGET_ACCESSIBILITY_FOCUS) != 0;
+    }
+
+    /** @hide */
+    public final void setTargetAccessibilityFocus(boolean targetsFocus) {
+        final int flags = getFlags();
+        nativeSetFlags(mNativePtr, targetsFocus
+                ? flags | FLAG_TARGET_ACCESSIBILITY_FOCUS
+                : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS);
+    }
+
     /**
      * Returns the time (in ms) when the user originally pressed down to start
      * a stream of position events.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/core/java/android/view/PhoneFallbackEventHandler.java
similarity index 96%
rename from policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
rename to core/java/android/view/PhoneFallbackEventHandler.java
index f291e89..fbf5732 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/core/java/android/view/PhoneFallbackEventHandler.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package android.view;
 
 import android.app.KeyguardManager;
 import android.app.SearchManager;
@@ -23,19 +23,14 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.media.AudioManager;
-import android.media.IAudioService;
 import android.media.session.MediaSessionLegacyHelper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
-import android.util.Log;
 import android.util.Slog;
-import android.view.View;
-import android.view.HapticFeedbackConstants;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
 
+/**
+ * @hide
+ */
 public class PhoneFallbackEventHandler implements FallbackEventHandler {
     private static String TAG = "PhoneFallbackEventHandler";
     private static final boolean DEBUG = false;
@@ -283,7 +278,7 @@
     }
 
     void sendCloseSystemWindows() {
-        PhoneWindowManager.sendCloseSystemWindows(mContext, null);
+        PhoneWindow.sendCloseSystemWindows(mContext, null);
     }
 
     private void handleMediaKeyEvent(KeyEvent keyEvent) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java b/core/java/android/view/PhoneLayoutInflater.java
similarity index 93%
rename from policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
rename to core/java/android/view/PhoneLayoutInflater.java
index df6fca4c..7d89a0b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
+++ b/core/java/android/view/PhoneLayoutInflater.java
@@ -14,37 +14,38 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package android.view;
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.View;
-import android.view.LayoutInflater;
 
+/**
+ * @hide
+ */
 public class PhoneLayoutInflater extends LayoutInflater {
     private static final String[] sClassPrefixList = {
         "android.widget.",
         "android.webkit.",
         "android.app."
     };
-    
+
     /**
      * Instead of instantiating directly, you should retrieve an instance
      * through {@link Context#getSystemService}
-     * 
+     *
      * @param context The Context in which in which to find resources and other
      *                application-specific things.
-     * 
+     *
      * @see Context#getSystemService
      */
     public PhoneLayoutInflater(Context context) {
         super(context);
     }
-    
+
     protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
         super(original, newContext);
     }
-    
+
     /** Override onCreateView to instantiate names that correspond to the
         widgets known to the Widget factory. If we don't find a match,
         call through to our super class.
@@ -64,7 +65,7 @@
 
         return super.onCreateView(name, attrs);
     }
-    
+
     public LayoutInflater cloneInContext(Context newContext) {
         return new PhoneLayoutInflater(this, newContext);
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/PhoneWindow.java
rename to core/java/android/view/PhoneWindow.java
index 153b67b..5f4d201 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package android.view;
 
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
@@ -22,6 +22,7 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
+import android.app.ActivityManagerNative;
 import android.app.SearchManager;
 import android.os.UserHandle;
 import com.android.internal.R;
@@ -72,31 +73,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedValue;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.InputEvent;
-import android.view.InputQueue;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewManager;
-import android.view.ViewParent;
-import android.view.ViewRootImpl;
-import android.view.ViewStub;
-import android.view.Window;
-import android.view.WindowInsets;
-import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
@@ -116,6 +92,8 @@
  * <p>
  * todo: need to pull the generic functionality out into a base class
  * in android.widget.
+ *
+ * @hide
  */
 public class PhoneWindow extends Window implements MenuBuilder.Callback {
 
@@ -1758,9 +1736,20 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN: {
-                int direction = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE
-                        : AudioManager.ADJUST_LOWER;
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                int direction = 0;
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_VOLUME_UP:
+                        direction = AudioManager.ADJUST_RAISE;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_DOWN:
+                        direction = AudioManager.ADJUST_LOWER;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_MUTE:
+                        direction = AudioManager.ADJUST_TOGGLE_MUTE;
+                        break;
+                }
                 // If we have a session send it the volume command, otherwise
                 // use the suggested stream.
                 if (mMediaController != null) {
@@ -1772,10 +1761,6 @@
                 }
                 return true;
             }
-            case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
-                return true;
-            }
             // These are all the recognized media key codes in
             // KeyEvent.isMediaKey()
             case KeyEvent.KEYCODE_MEDIA_PLAY:
@@ -3165,7 +3150,7 @@
 
             // If the user is chording a menu shortcut, release the chord since
             // this window lost focus
-            if (!hasWindowFocus && mPanelChordingKey != 0) {
+            if (hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus && mPanelChordingKey != 0) {
                 closePanel(FEATURE_OPTIONS_PANEL);
             }
 
@@ -3479,6 +3464,10 @@
         if (!mForcedNavigationBarColor) {
             mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
         }
+        if (a.getBoolean(R.styleable.Window_windowHasLightStatusBar, false)) {
+            decor.setSystemUiVisibility(
+                    decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+        }
 
         if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
@@ -4743,11 +4732,20 @@
     }
 
     void sendCloseSystemWindows() {
-        PhoneWindowManager.sendCloseSystemWindows(getContext(), null);
+        sendCloseSystemWindows(getContext(), null);
     }
 
     void sendCloseSystemWindows(String reason) {
-        PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
+        sendCloseSystemWindows(getContext(), reason);
+    }
+
+    public static void sendCloseSystemWindows(Context context, String reason) {
+        if (ActivityManagerNative.isSystemReady()) {
+            try {
+                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+            } catch (RemoteException e) {
+            }
+        }
     }
 
     @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 259367e..ad5d651 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2544,6 +2544,20 @@
     public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000;
 
     /**
+     * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that
+     * is compatible with light status bar backgrounds.
+     *
+     * <p>For this to take effect, the window must request
+     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
+     *         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not
+     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS
+     *         FLAG_TRANSLUCENT_STATUS}.
+     *
+     * @see android.R.attr#windowHasLightStatusBar
+     */
+    public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
+
+    /**
      * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead.
      */
     public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE;
@@ -3568,7 +3582,7 @@
      * @param attrs The attributes of the XML tag that is inflating the view.
      * @see #View(Context, AttributeSet, int)
      */
-    public View(Context context, AttributeSet attrs) {
+    public View(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
@@ -3589,7 +3603,7 @@
      *        the view. Can be 0 to not look for defaults.
      * @see #View(Context, AttributeSet)
      */
-    public View(Context context, AttributeSet attrs, int defStyleAttr) {
+    public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
@@ -3626,7 +3640,7 @@
      *        to not look for defaults.
      * @see #View(Context, AttributeSet, int)
      */
-    public View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         this(context);
 
         final TypedArray a = context.obtainStyledAttributes(
@@ -4676,7 +4690,7 @@
      *
      * @see #setClickable(boolean)
      */
-    public void setOnClickListener(OnClickListener l) {
+    public void setOnClickListener(@Nullable OnClickListener l) {
         if (!isClickable()) {
             setClickable(true);
         }
@@ -4700,7 +4714,7 @@
      *
      * @see #setLongClickable(boolean)
      */
-    public void setOnLongClickListener(OnLongClickListener l) {
+    public void setOnLongClickListener(@Nullable OnLongClickListener l) {
         if (!isLongClickable()) {
             setLongClickable(true);
         }
@@ -5416,7 +5430,7 @@
      */
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         event.setSource(this);
-        event.setClassName(View.class.getName());
+        event.setClassName(getAccessibilityClassName());
         event.setPackageName(getContext().getPackageName());
         event.setEnabled(isEnabled());
         event.setContentDescription(mContentDescription);
@@ -5522,12 +5536,23 @@
     }
 
     /**
-     * Gets the location of this view in screen coordintates.
+     * Gets the location of this view in screen coordinates.
      *
      * @param outRect The output location
      * @hide
      */
     public void getBoundsOnScreen(Rect outRect) {
+        getBoundsOnScreen(outRect, false);
+    }
+
+    /**
+     * Gets the location of this view in screen coordinates.
+     *
+     * @param outRect The output location
+     * @param clipToParent Whether to clip child bounds to the parent ones.
+     * @hide
+     */
+    public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
         if (mAttachInfo == null) {
             return;
         }
@@ -5547,6 +5572,13 @@
 
             position.offset(-parentView.mScrollX, -parentView.mScrollY);
 
+            if (clipToParent) {
+                position.left = Math.max(position.left, 0);
+                position.top = Math.max(position.top, 0);
+                position.right = Math.min(position.right, parentView.getWidth());
+                position.bottom = Math.min(position.bottom, parentView.getHeight());
+            }
+
             if (!parentView.hasIdentityMatrix()) {
                 parentView.getMatrix().mapRect(position);
             }
@@ -5568,6 +5600,26 @@
     }
 
     /**
+     * Return the class name of this object to be used for accessibility purposes.
+     * Subclasses should only override this if they are implementing something that
+     * should be seen as a completely new class of view when used by accessibility,
+     * unrelated to the class it is deriving from.  This is used to fill in
+     * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}.
+     */
+    public CharSequence getAccessibilityClassName() {
+        return View.class.getName();
+    }
+
+    /**
+     * Called when assist data is being retrieved from a view as part of
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+     * @param data
+     * @param extras
+     */
+    public void onProvideAssistData(ViewAssistData data, Bundle extras) {
+    }
+
+    /**
      * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
@@ -5580,7 +5632,7 @@
         getDrawingRect(bounds);
         info.setBoundsInParent(bounds);
 
-        getBoundsOnScreen(bounds);
+        getBoundsOnScreen(bounds, true);
         info.setBoundsInScreen(bounds);
 
         ViewParent parent = getParentForAccessibility();
@@ -5649,7 +5701,7 @@
         info.setVisibleToUser(isVisibleToUser());
 
         info.setPackageName(mContext.getPackageName());
-        info.setClassName(View.class.getName());
+        info.setClassName(getAccessibilityClassName());
         info.setContentDescription(getContentDescription());
 
         info.setEnabled(isEnabled());
@@ -5776,142 +5828,6 @@
     }
 
     /**
-     * Computes a point on which a sequence of a down/up event can be sent to
-     * trigger clicking this view. This method is for the exclusive use by the
-     * accessibility layer to determine where to send a click event in explore
-     * by touch mode.
-     *
-     * @param interactiveRegion The interactive portion of this window.
-     * @param outPoint The point to populate.
-     * @return True of such a point exists.
-     */
-    boolean computeClickPointInScreenForAccessibility(Region interactiveRegion,
-            Point outPoint) {
-        // Since the interactive portion of the view is a region but as a view
-        // may have a transformation matrix which cannot be applied to a
-        // region we compute the view bounds rectangle and all interactive
-        // predecessor's and sibling's (siblings of predecessors included)
-        // rectangles that intersect the view bounds. At the
-        // end if the view was partially covered by another interactive
-        // view we compute the view's interactive region and pick a point
-        // on its boundary path as regions do not offer APIs to get inner
-        // points. Note that the the code is optimized to fail early and
-        // avoid unnecessary allocations plus computations.
-
-        // The current approach has edge cases that may produce false
-        // positives or false negatives. For example, a portion of the
-        // view may be covered by an interactive descendant of a
-        // predecessor, which we do not compute. Also a view may be handling
-        // raw touch events instead registering click listeners, which
-        // we cannot compute. Despite these limitations this approach will
-        // work most of the time and it is a huge improvement over just
-        // blindly sending the down and up events in the center of the
-        // view.
-
-        // Cannot click on an unattached view.
-        if (mAttachInfo == null) {
-            return false;
-        }
-
-        // Attached to an invisible window means this view is not visible.
-        if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
-            return false;
-        }
-
-        RectF bounds = mAttachInfo.mTmpTransformRect;
-        bounds.set(0, 0, getWidth(), getHeight());
-        List<RectF> intersections = mAttachInfo.mTmpRectList;
-        intersections.clear();
-
-        if (mParent instanceof ViewGroup) {
-            ViewGroup parentGroup = (ViewGroup) mParent;
-            if (!parentGroup.translateBoundsAndIntersectionsInWindowCoordinates(
-                    this, bounds, intersections)) {
-                intersections.clear();
-                return false;
-            }
-        }
-
-        // Take into account the window location.
-        final int dx = mAttachInfo.mWindowLeft;
-        final int dy = mAttachInfo.mWindowTop;
-        bounds.offset(dx, dy);
-        offsetRects(intersections, dx, dy);
-
-        if (intersections.isEmpty() && interactiveRegion == null) {
-            outPoint.set((int) bounds.centerX(), (int) bounds.centerY());
-        } else {
-            // This view is partially covered by other views, then compute
-            // the not covered region and pick a point on its boundary.
-            Region region = new Region();
-            region.set((int) bounds.left, (int) bounds.top,
-                    (int) bounds.right, (int) bounds.bottom);
-
-            final int intersectionCount = intersections.size();
-            for (int i = intersectionCount - 1; i >= 0; i--) {
-                RectF intersection = intersections.remove(i);
-                region.op((int) intersection.left, (int) intersection.top,
-                        (int) intersection.right, (int) intersection.bottom,
-                        Region.Op.DIFFERENCE);
-            }
-
-            // If the view is completely covered, done.
-            if (region.isEmpty()) {
-                return false;
-            }
-
-            // Take into account the interactive portion of the window
-            // as the rest is covered by other windows. If no such a region
-            // then the whole window is interactive.
-            if (interactiveRegion != null) {
-                region.op(interactiveRegion, Region.Op.INTERSECT);
-            }
-
-            // Take into account the window bounds.
-            final View root = getRootView();
-            if (root != null) {
-                region.op(dx, dy, root.getWidth() + dx, root.getHeight() + dy, Region.Op.INTERSECT);
-            }
-
-            // If the view is completely covered, done.
-            if (region.isEmpty()) {
-                return false;
-            }
-
-            // Try a shortcut here.
-            if (region.isRect()) {
-                Rect regionBounds = mAttachInfo.mTmpInvalRect;
-                region.getBounds(regionBounds);
-                outPoint.set(regionBounds.centerX(), regionBounds.centerY());
-                return true;
-            }
-
-            // Get the a point on the region boundary path.
-            Path path = region.getBoundaryPath();
-            PathMeasure pathMeasure = new PathMeasure(path, false);
-            final float[] coordinates = mAttachInfo.mTmpTransformLocation;
-
-            // Without loss of generality pick a point.
-            final float point = pathMeasure.getLength() * 0.01f;
-            if (!pathMeasure.getPosTan(point, coordinates, null)) {
-                return false;
-            }
-
-            outPoint.set(Math.round(coordinates[0]), Math.round(coordinates[1]));
-        }
-
-        return true;
-    }
-
-    static void offsetRects(List<RectF> rects, float offsetX, float offsetY) {
-        final int rectCount = rects.size();
-        for (int i = 0; i < rectCount; i++) {
-            RectF intersection = rects.get(i);
-            intersection.offset(offsetX, offsetY);
-        }
-    }
-
-    /**
      * Returns the delegate for implementing accessibility support via
      * composition. For more details see {@link AccessibilityDelegate}.
      *
@@ -6780,7 +6696,6 @@
     @RemotableViewMethod
     public void setVisibility(@Visibility int visibility) {
         setFlags(visibility, VISIBILITY_MASK);
-        if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false);
     }
 
     /**
@@ -8526,6 +8441,16 @@
      * @return True if the event was handled by the view, false otherwise.
      */
     public boolean dispatchTouchEvent(MotionEvent event) {
+        // If the event should be handled by accessibility focus first.
+        if (event.isTargetAccessibilityFocus()) {
+            // We don't have focus or no virtual descendant has it, do not handle the event.
+            if (!isAccessibilityFocusedViewOrHost()) {
+                return false;
+            }
+            // We have focus and got the event, then use normal event dispatch.
+            event.setTargetAccessibilityFocus(false);
+        }
+
         boolean result = false;
 
         if (mInputEventConsistencyVerifier != null) {
@@ -8568,6 +8493,11 @@
         return result;
     }
 
+    boolean isAccessibilityFocusedViewOrHost() {
+        return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl()
+                .getAccessibilityFocusedHost() == this);
+    }
+
     /**
      * Filter the touch event to apply security policies.
      *
@@ -8806,20 +8736,28 @@
     }
 
     /**
-     * Called when the visibility of the view or an ancestor of the view is changed.
-     * @param changedView The view whose visibility changed. Could be 'this' or
-     * an ancestor view.
-     * @param visibility The new visibility of changedView: {@link #VISIBLE},
-     * {@link #INVISIBLE} or {@link #GONE}.
+     * Called when the visibility of the view or an ancestor of the view has
+     * changed.
+     *
+     * @param changedView The view whose visibility changed. May be
+     *                    {@code this} or an ancestor view.
+     * @param visibility The new visibility, one of {@link #VISIBLE},
+     *                   {@link #INVISIBLE} or {@link #GONE}.
      */
     protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
-        if (visibility == VISIBLE) {
+        final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
+        if (visible) {
             if (mAttachInfo != null) {
                 initialAwakenScrollBars();
             } else {
                 mPrivateFlags |= PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH;
             }
         }
+
+        final Drawable dr = mBackground;
+        if (dr != null && visible != dr.isVisible()) {
+            dr.setVisible(visible, false);
+        }
     }
 
     /**
@@ -12958,7 +12896,7 @@
                         Interpolator.Result.FREEZE_END) {
                     cache.state = ScrollabilityCache.OFF;
                 } else {
-                    cache.scrollBar.setAlpha(Math.round(values[0]));
+                    cache.scrollBar.mutate().setAlpha(Math.round(values[0]));
                 }
 
                 // This will make the scroll bars inval themselves after
@@ -12968,7 +12906,7 @@
             } else {
                 // We're just on -- but we may have been fading before so
                 // reset alpha
-                cache.scrollBar.setAlpha(255);
+                cache.scrollBar.mutate().setAlpha(255);
             }
 
 
@@ -14885,10 +14823,9 @@
     void setDisplayListProperties(RenderNode renderNode) {
         if (renderNode != null) {
             renderNode.setHasOverlappingRendering(hasOverlappingRendering());
-            if (mParent instanceof ViewGroup) {
-                renderNode.setClipToBounds(
-                        (((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
-            }
+            renderNode.setClipToBounds(mParent instanceof ViewGroup
+                    && ((ViewGroup) mParent).getClipChildren());
+
             float alpha = 1;
             if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
                     ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -17172,6 +17109,7 @@
      * @param id The id to search for.
      * @return The view that has the given id in the hierarchy or null
      */
+    @Nullable
     public final View findViewById(int id) {
         if (id < 0) {
             return null;
diff --git a/core/java/android/view/ViewAssistData.java b/core/java/android/view/ViewAssistData.java
new file mode 100644
index 0000000..74436ea
--- /dev/null
+++ b/core/java/android/view/ViewAssistData.java
@@ -0,0 +1,32 @@
+/*
+ * 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.view;
+
+/**
+ * Container for storing data generated by {@link View#onProvideAssistData
+ * View.onProvideAssistData}.
+ */
+public abstract class ViewAssistData {
+    public abstract void setText(CharSequence text);
+    public abstract void setText(CharSequence text, int selectionStart, int selectionEnd);
+    public abstract void setHint(CharSequence hint);
+
+    public abstract CharSequence getText();
+    public abstract int getTextSelectionStart();
+    public abstract int getTextSelectionEnd();
+    public abstract CharSequence getHint();
+}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 49e4efa..504a758 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -474,9 +474,6 @@
     @ViewDebug.ExportedProperty(category = "layout")
     private int mChildCountWithTransientState = 0;
 
-    // Iterator over the children in decreasing Z order (top children first).
-    private OrderedChildIterator mOrderedChildIterator;
-
     /**
      * Currently registered axes for nested scrolling. Flag set consisting of
      * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
@@ -782,144 +779,6 @@
     }
 
     /**
-     * Translates the given bounds and intersections from child coordinates to
-     * local coordinates. In case any interactive sibling of the calling child
-     * covers the latter, a new intersections is added to the intersection list.
-     * This method is for the exclusive use by the accessibility layer to compute
-     * a point where a sequence of down and up events would click on a view.
-     *
-     * @param child The child making the call.
-     * @param bounds The bounds to translate in child coordinates.
-     * @param intersections The intersections of interactive views covering the child.
-     * @return True if the bounds and intersections were computed, false otherwise.
-     */
-    boolean translateBoundsAndIntersectionsInWindowCoordinates(View child,
-            RectF bounds, List<RectF> intersections) {
-        // Not attached, done.
-        if (mAttachInfo == null) {
-            return false;
-        }
-
-        if (getAlpha() <= 0 || getTransitionAlpha() <= 0 ||
-                getVisibility() != VISIBLE) {
-            // Cannot click on a view with an invisible predecessor.
-            return false;
-        }
-
-        // Compensate for the child transformation.
-        if (!child.hasIdentityMatrix()) {
-            Matrix matrix = child.getMatrix();
-            matrix.mapRect(bounds);
-            final int intersectionCount = intersections.size();
-            for (int i = 0; i < intersectionCount; i++) {
-                RectF intersection = intersections.get(i);
-                matrix.mapRect(intersection);
-            }
-        }
-
-        // Translate the bounds from child to parent coordinates.
-        final int dx = child.mLeft - mScrollX;
-        final int dy = child.mTop - mScrollY;
-        bounds.offset(dx, dy);
-        offsetRects(intersections, dx, dy);
-
-        // If the bounds do not intersect our bounds, done.
-        if (!bounds.intersects(0, 0, getWidth(), getHeight())) {
-            return false;
-        }
-
-        // Clip the bounds by our bounds.
-        bounds.left = Math.max(bounds.left, 0);
-        bounds.top = Math.max(bounds.top, 0);
-        bounds.right = Math.min(bounds.right, getWidth());
-        bounds.bottom = Math.min(bounds.bottom, getHeight());
-
-        Iterator<View> iterator = obtainOrderedChildIterator();
-        while (iterator.hasNext()) {
-            View sibling = iterator.next();
-
-            // We care only about siblings over the child.
-            if (sibling == child) {
-                break;
-            }
-
-            // Ignore invisible views as they are not interactive.
-            if (!isVisible(sibling)) {
-                continue;
-            }
-
-            // Compute the sibling bounds in its coordinates.
-            RectF siblingBounds = mAttachInfo.mTmpTransformRect1;
-            siblingBounds.set(0, 0, sibling.getWidth(), sibling.getHeight());
-
-            // Translate the sibling bounds to our coordinates.
-            offsetChildRectToMyCoords(siblingBounds, sibling);
-
-            // Compute the intersection between the child and the sibling.
-            if (siblingBounds.intersect(bounds)) {
-                // Conservatively we consider an overlapping sibling to be
-                // interactive and ignore it. This is not ideal as if the
-                // sibling completely covers the view despite handling no
-                // touch events we will not be able to click on the view.
-                intersections.add(siblingBounds);
-            }
-        }
-
-        releaseOrderedChildIterator();
-
-        if (mParent instanceof ViewGroup) {
-            ViewGroup parentGroup = (ViewGroup) mParent;
-            return parentGroup.translateBoundsAndIntersectionsInWindowCoordinates(
-                    this, bounds, intersections);
-        }
-
-        return true;
-    }
-
-    private void offsetChildRectToMyCoords(RectF rect, View child) {
-        if (!child.hasIdentityMatrix()) {
-            child.getMatrix().mapRect(rect);
-        }
-        final int childDx = child.mLeft - mScrollX;
-        final int childDy = child.mTop - mScrollY;
-        rect.offset(childDx, childDy);
-    }
-
-    private static boolean isVisible(View view) {
-        return (view.getAlpha() > 0 && view.getTransitionAlpha() > 0 &&
-                view.getVisibility() == VISIBLE);
-    }
-
-    /**
-     * Obtains the iterator to traverse the children in a descending Z order.
-     * Only one party can use the iterator at any given time and you cannot
-     * modify the children while using this iterator. Acquisition if already
-     * obtained is an error.
-     *
-     * @return The child iterator.
-     */
-    OrderedChildIterator obtainOrderedChildIterator() {
-        if (mOrderedChildIterator == null) {
-            mOrderedChildIterator = new OrderedChildIterator();
-        } else if (mOrderedChildIterator.isInitialized()) {
-            throw new IllegalStateException("Already obtained");
-        }
-        mOrderedChildIterator.initialize();
-        return mOrderedChildIterator;
-    }
-
-    /**
-     * Releases the iterator to traverse the children in a descending Z order.
-     * Release if not obtained is an error.
-     */
-    void releaseOrderedChildIterator() {
-        if (mOrderedChildIterator == null || !mOrderedChildIterator.isInitialized()) {
-            throw new IllegalStateException("Not obtained");
-        }
-        mOrderedChildIterator.release();
-    }
-
-    /**
      * Called when a child view has changed whether or not it is tracking transient state.
      */
     public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
@@ -1349,7 +1208,7 @@
      * {@inheritDoc}
      */
     public void bringChildToFront(View child) {
-        int index = indexOfChild(child);
+        final int index = indexOfChild(child);
         if (index >= 0) {
             removeFromArray(index);
             addInArray(child, mChildrenCount);
@@ -2074,6 +1933,12 @@
             mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
         }
 
+        // If the event targets the accessibility focused view and this is it, start
+        // normal event dispatch. Maybe a descendant is what will handle the click.
+        if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
+            ev.setTargetAccessibilityFocus(false);
+        }
+
         boolean handled = false;
         if (onFilterTouchEventForSecurity(ev)) {
             final int action = ev.getAction();
@@ -2105,6 +1970,12 @@
                 intercepted = true;
             }
 
+            // If intercepted, start normal event dispatch. Also if there is already
+            // a view that is handling the gesture, do normal event dispatch.
+            if (intercepted || mFirstTouchTarget != null) {
+                ev.setTargetAccessibilityFocus(false);
+            }
+
             // Check for cancelation.
             final boolean canceled = resetCancelNextUpFlag(this)
                     || actionMasked == MotionEvent.ACTION_CANCEL;
@@ -2114,6 +1985,15 @@
             TouchTarget newTouchTarget = null;
             boolean alreadyDispatchedToNewTouchTarget = false;
             if (!canceled && !intercepted) {
+
+                // If the event is targeting accessiiblity focus we give it to the
+                // view that has accessibility focus and if it does not handle it
+                // we clear the flag and dispatch the event to all children as usual.
+                // We are looking up the accessibility focused host to avoid keeping
+                // state since these events are very rare.
+                View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
+                        ? findChildWithAccessibilityFocus() : null;
+
                 if (actionMasked == MotionEvent.ACTION_DOWN
                         || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                         || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
@@ -2140,8 +2020,22 @@
                                     ? getChildDrawingOrder(childrenCount, i) : i;
                             final View child = (preorderedList == null)
                                     ? children[childIndex] : preorderedList.get(childIndex);
+
+                            // If there is a view that has accessibility focus we want it
+                            // to get the event first and if not handled we will perform a
+                            // normal dispatch. We may do a double iteration but this is
+                            // safer given the timeframe.
+                            if (childWithAccessibilityFocus != null) {
+                                if (childWithAccessibilityFocus != child) {
+                                    continue;
+                                }
+                                childWithAccessibilityFocus = null;
+                                i = childrenCount - 1;
+                            }
+
                             if (!canViewReceivePointerEvents(child)
                                     || !isTransformedTouchPointInView(x, y, child, null)) {
+                                ev.setTargetAccessibilityFocus(false);
                                 continue;
                             }
 
@@ -2174,6 +2068,10 @@
                                 alreadyDispatchedToNewTouchTarget = true;
                                 break;
                             }
+
+                            // The accessibility focus didn't handle the event, so clear
+                            // the flag and do a normal dispatch to all children.
+                            ev.setTargetAccessibilityFocus(false);
                         }
                         if (preorderedList != null) preorderedList.clear();
                     }
@@ -2246,6 +2144,34 @@
     }
 
     /**
+     * Finds the child which has accessibility focus.
+     *
+     * @return The child that has focus.
+     */
+    private View findChildWithAccessibilityFocus() {
+        ViewRootImpl viewRoot = getViewRootImpl();
+        if (viewRoot == null) {
+            return null;
+        }
+
+        View current = viewRoot.getAccessibilityFocusedHost();
+        if (current == null) {
+            return null;
+        }
+
+        ViewParent parent = current.getParent();
+        while (parent instanceof View) {
+            if (parent == this) {
+                return current;
+            }
+            current = (View) parent;
+            parent = current.getParent();
+        }
+
+        return null;
+    }
+
+    /**
      * Resets all touch state in preparation for a new cycle.
      */
     private void resetTouchState() {
@@ -2817,6 +2743,9 @@
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
+        if (getAccessibilityNodeProvider() != null) {
+            return;
+        }
         if (mAttachInfo != null) {
             final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
             childrenForAccessibility.clear();
@@ -3842,7 +3771,7 @@
      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      *
      * @param child the child view to add
-     * @param index the position at which to add the child
+     * @param index the position at which to add the child or -1 to add last
      * @param params the layout parameters to set on the child
      */
     public void addView(View child, int index, LayoutParams params) {
@@ -3958,7 +3887,7 @@
      * If index is negative, it means put it at the end of the list.
      *
      * @param child the view to add to the group
-     * @param index the index at which the child must be added
+     * @param index the index at which the child must be added or -1 to add last
      * @param params the layout parameters to associate with the child
      * @return true if the child was added, false otherwise
      */
@@ -3973,7 +3902,7 @@
      * If index is negative, it means put it at the end of the list.
      *
      * @param child the view to add to the group
-     * @param index the index at which the child must be added
+     * @param index the index at which the child must be added or -1 to add last
      * @param params the layout parameters to associate with the child
      * @param preventRequestLayout if true, calling this method will not trigger a
      *        layout request on child
@@ -7408,57 +7337,4 @@
 
         canvas.drawLines(sDebugLines, paint);
     }
-
-    private final class OrderedChildIterator implements Iterator<View> {
-        private List<View> mOrderedChildList;
-        private boolean mUseCustomOrder;
-        private int mCurrentIndex;
-        private boolean mInitialized;
-
-        public void initialize() {
-            mOrderedChildList = buildOrderedChildList();
-            mUseCustomOrder = (mOrderedChildList == null)
-                    && isChildrenDrawingOrderEnabled();
-            mCurrentIndex = mChildrenCount - 1;
-            mInitialized = true;
-        }
-
-        public void release() {
-            if (mOrderedChildList != null) {
-                mOrderedChildList.clear();
-            }
-            mUseCustomOrder = false;
-            mCurrentIndex = 0;
-            mInitialized = false;
-        }
-
-        public boolean isInitialized() {
-            return mInitialized;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return (mCurrentIndex >= 0);
-        }
-
-        @Override
-        public View next() {
-            if (!hasNext()) {
-                throw new NoSuchElementException("No such element");
-            }
-            return getChild(mCurrentIndex--);
-        }
-
-        private View getChild(int index) {
-            final int childIndex = mUseCustomOrder
-                    ? getChildDrawingOrder(mChildrenCount, index) : index;
-            return (mOrderedChildList == null)
-                    ? mChildren[childIndex] : mOrderedChildList.get(childIndex);
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 87d9a58..fb2a8d8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -76,7 +76,6 @@
 
 import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.policy.PolicyManager;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
 
@@ -386,7 +385,7 @@
         mViewConfiguration = ViewConfiguration.get(context);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
-        mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
+        mFallbackEventHandler = new PhoneFallbackEventHandler(context);
         mChoreographer = Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         loadSystemProperties();
@@ -472,8 +471,10 @@
 
                 // Compute surface insets required to draw at specified Z value.
                 // TODO: Use real shadow insets for a constant max Z.
-                final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
-                attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                if (!attrs.hasManualSurfaceInsets) {
+                    final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+                    attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                }
 
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
@@ -649,6 +650,10 @@
         return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
     }
 
+    public CharSequence getTitle() {
+        return mWindowAttributes.getTitle();
+    }
+
     void destroyHardwareResources() {
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
@@ -760,6 +765,7 @@
             final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
             final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
             final int oldSoftInputMode = mWindowAttributes.softInputMode;
+            final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
 
             // Keep track of the actual window flags supplied by the client.
             mClientWindowLayoutFlags = attrs.flags;
@@ -786,6 +792,7 @@
             // Restore old surface insets.
             mWindowAttributes.surfaceInsets.set(
                     oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+            mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
 
             applyKeepScreenOnFlag(mWindowAttributes);
 
@@ -1326,6 +1333,11 @@
             }
         }
 
+        // Non-visible windows can't hold accessibility focus.
+        if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
+            host.clearAccessibilityFocus();
+        }
+
         // Execute enqueued actions on every traversal in case a detached view enqueued an action
         getRunQueue().executeActions(mAttachInfo.mHandler);
 
@@ -2703,7 +2715,7 @@
 
         final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
         if (provider == null) {
-            host.getBoundsOnScreen(bounds);
+            host.getBoundsOnScreen(bounds, true);
         } else if (mAccessibilityFocusedVirtualView != null) {
             mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
         } else {
@@ -6835,26 +6847,6 @@
         }
 
         @Override
-        public void computeClickPointInScreen(long accessibilityNodeId, Region interactiveRegion,
-                int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
-            ViewRootImpl viewRootImpl = mViewRootImpl.get();
-            if (viewRootImpl != null && viewRootImpl.mView != null) {
-                viewRootImpl.getAccessibilityInteractionController()
-                        .computeClickPointInScreenClientThread(accessibilityNodeId,
-                                interactiveRegion, interactionId, callback, interrogatingPid,
-                                interrogatingTid, spec);
-            } else {
-                // We cannot make the call and notify the caller so it does not wait.
-                try {
-                    callback.setComputeClickPointInScreenActionResult(null, interactionId);
-                } catch (RemoteException re) {
-                    /* best effort - ignore */
-                }
-            }
-        }
-
-        @Override
         public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
                 String viewId, Region interactiveRegion, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int flags,
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 3f2f3a5..8964862 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -42,10 +42,8 @@
  * area, default key processing, etc.
  *
  * <p>The only existing implementation of this abstract class is
- * android.policy.PhoneWindow, which you should instantiate when needing a
- * Window.  Eventually that class will be refactored and a factory method
- * added for creating Window instances without knowing about a particular
- * implementation.
+ * android.view.PhoneWindow, which you should instantiate when needing a
+ * Window.
  */
 public abstract class Window {
     /** Flag for the "options panel" feature.  This is enabled by default. */
@@ -102,10 +100,12 @@
      */
     public static final int FEATURE_SWIPE_TO_DISMISS = 11;
     /**
-     * Flag for requesting that window content changes should be represented
-     * with scenes and transitions.
+     * Flag for requesting that window content changes should be animated using a
+     * TransitionManager.
      *
-     * TODO Add docs
+     * <p>The TransitionManager is set using
+     * {@link #setTransitionManager(android.transition.TransitionManager)}. If none is set,
+     * a default TransitionManager will be used.</p>
      *
      * @see #setContentView
      */
@@ -984,6 +984,7 @@
      *
      * @return The view if found or null otherwise.
      */
+    @Nullable
     public View findViewById(int id) {
         return getDecorView().findViewById(id);
     }
@@ -1019,10 +1020,16 @@
      * <p>Note that calling this function "locks in" various characteristics
      * of the window that can not, from this point forward, be changed: the
      * features that have been requested with {@link #requestFeature(int)},
-     * and certain window flags as described in {@link #setFlags(int, int)}.
+     * and certain window flags as described in {@link #setFlags(int, int)}.</p>
+     *
+     * <p>If {@link #FEATURE_CONTENT_TRANSITIONS} is set, the window's
+     * TransitionManager will be used to animate content from the current
+     * content View to view.</p>
      *
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
+     * @see #getTransitionManager()
+     * @see #setTransitionManager(android.transition.TransitionManager)
      */
     public abstract void setContentView(View view, ViewGroup.LayoutParams params);
 
@@ -1467,6 +1474,7 @@
      * {@link #setContentView}) if {@link #FEATURE_CONTENT_TRANSITIONS} has been granted.</p>
      *
      * @return This window's content TransitionManager or null if none is set.
+     * @attr ref android.R.styleable#Window_windowContentTransitionManager
      */
     public TransitionManager getTransitionManager() {
         return null;
@@ -1477,6 +1485,7 @@
      * Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
      *
      * @param tm The TransitionManager to use for scene changes.
+     * @attr ref android.R.styleable#Window_windowContentTransitionManager
      */
     public void setTransitionManager(TransitionManager tm) {
         throw new UnsupportedOperationException();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 12b310f..905d6d7 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.SystemApi;
 import android.app.Presentation;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -1325,6 +1326,16 @@
          * @hide
          */
         public final Rect surfaceInsets = new Rect();
+
+        /**
+         * Whether the surface insets have been manually set. When set to
+         * {@code false}, the view root will automatically determine the
+         * appropriate surface insets.
+         *
+         * @see #surfaceInsets
+         * @hide
+         */
+        public boolean hasManualSurfaceInsets;
     
         /**
          * The desired bitmap format.  May be one of the constants in
@@ -1583,7 +1594,19 @@
         public final CharSequence getTitle() {
             return mTitle;
         }
-    
+
+        /** @hide */
+        @SystemApi
+        public final void setUserActivityTimeout(long timeout) {
+            userActivityTimeout = timeout;
+        }
+
+        /** @hide */
+        @SystemApi
+        public final long getUserActivityTimeout() {
+            return userActivityTimeout;
+        }
+
         public int describeContents() {
             return 0;
         }
@@ -1621,6 +1644,7 @@
             out.writeInt(surfaceInsets.top);
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
+            out.writeInt(hasManualSurfaceInsets ? 1 : 0);
             out.writeInt(needsMenuKey);
         }
 
@@ -1669,6 +1693,7 @@
             surfaceInsets.top = in.readInt();
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
+            hasManualSurfaceInsets = in.readInt() != 0;
             needsMenuKey = in.readInt();
         }
 
@@ -1851,6 +1876,11 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (hasManualSurfaceInsets != o.hasManualSurfaceInsets) {
+                hasManualSurfaceInsets = o.hasManualSurfaceInsets;
+                changes |= SURFACE_INSETS_CHANGED;
+            }
+
             if (needsMenuKey != o.needsMenuKey) {
                 needsMenuKey = o.needsMenuKey;
                 changes |= NEEDS_MENU_KEY_CHANGED;
@@ -1959,8 +1989,11 @@
             if (userActivityTimeout >= 0) {
                 sb.append(" userActivityTimeout=").append(userActivityTimeout);
             }
-            if (!surfaceInsets.equals(Insets.NONE)) {
+            if (!surfaceInsets.equals(Insets.NONE) || hasManualSurfaceInsets) {
                 sb.append(" surfaceInsets=").append(surfaceInsets);
+                if (hasManualSurfaceInsets) {
+                    sb.append(" (manual)");
+                }
             }
             if (needsMenuKey != NEEDS_MENU_UNSET) {
                 sb.append(" needsMenuKey=");
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index ed17e3f..279627a 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -190,6 +190,39 @@
         }
     }
 
+    public ArrayList<ViewRootImpl> getRootViews(IBinder token) {
+        ArrayList<ViewRootImpl> views = new ArrayList<>();
+        synchronized (mLock) {
+            final int numRoots = mRoots.size();
+            for (int i = 0; i < numRoots; ++i) {
+                WindowManager.LayoutParams params = mParams.get(i);
+                if (params.token == null) {
+                    continue;
+                }
+                if (params.token != token) {
+                    boolean isChild = false;
+                    if (params.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
+                            && params.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        for (int j = 0 ; j < numRoots; ++j) {
+                            View viewj = mViews.get(j);
+                            WindowManager.LayoutParams paramsj = mParams.get(j);
+                            if (params.token == viewj.getWindowToken()
+                                    && paramsj.token == token) {
+                                isChild = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (!isChild) {
+                        continue;
+                    }
+                }
+                views.add(mRoots.get(i));
+            }
+        }
+        return views;
+    }
+
     public View getRootView(String name) {
         synchronized (mLock) {
             for (int i = mRoots.size() - 1; i >= 0; --i) {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index ff1fde7..3f35612 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
@@ -105,6 +106,13 @@
     public final static String EXTRA_HDMI_PLUGGED_STATE = "state";
 
     /**
+     * Set to {@code true} when intent was invoked from pressing the home key.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY";
+
+    /**
      * Pass this event to the user / app.  To be returned from
      * {@link #interceptKeyBeforeQueueing}.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 374f7e0..cefd34d 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -99,8 +99,6 @@
 
     private boolean mPerformAccessibilityActionResult;
 
-    private Point mComputeClickPointResult;
-
     private Message mSameThreadMessage;
 
     private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
@@ -522,43 +520,6 @@
         return false;
     }
 
-    /**
-     * Computes a point in screen coordinates where sending a down/up events would
-     * perform a click on an {@link AccessibilityNodeInfo}.
-     *
-     * @param connectionId The id of a connection for interacting with the system.
-     * @param accessibilityWindowId A unique window id. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
-     *     to query the currently active window.
-     * @param accessibilityNodeId A unique view id or virtual descendant id from
-     *     where to start the search. Use
-     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
-     *     to start from the root.
-     * @return Point the click point of null if no such point.
-     */
-    public Point computeClickPointInScreen(int connectionId, int accessibilityWindowId,
-            long accessibilityNodeId) {
-        try {
-            IAccessibilityServiceConnection connection = getConnection(connectionId);
-            if (connection != null) {
-                final int interactionId = mInteractionIdCounter.getAndIncrement();
-                final boolean success = connection.computeClickPointInScreen(
-                        accessibilityWindowId, accessibilityNodeId,
-                        interactionId, this, Thread.currentThread().getId());
-                if (success) {
-                    return getComputeClickPointInScreenResultAndClear(interactionId);
-                }
-            } else {
-                if (DEBUG) {
-                    Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
-                }
-            }
-        } catch (RemoteException re) {
-            Log.w(LOG_TAG, "Error while calling remote computeClickPointInScreen", re);
-        }
-        return null;
-    }
-
     public void clearCache() {
         sAccessibilityCache.clear();
     }
@@ -674,34 +635,6 @@
     }
 
     /**
-     * Gets the result of a request to compute a point in screen for clicking on a node.
-     *
-     * @param interactionId The interaction id to match the result with the request.
-     * @return The point or null if no such point.
-     */
-    private Point getComputeClickPointInScreenResultAndClear(int interactionId) {
-        synchronized (mInstanceLock) {
-            final boolean success = waitForResultTimedLocked(interactionId);
-            Point result = success ? mComputeClickPointResult : null;
-            clearResultLocked();
-            return result;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void setComputeClickPointInScreenActionResult(Point point, int interactionId) {
-        synchronized (mInstanceLock) {
-            if (interactionId > mInteractionId) {
-                mComputeClickPointResult = point;
-                mInteractionId = interactionId;
-            }
-            mInstanceLock.notifyAll();
-        }
-    }
-
-    /**
      * Clears the result state.
      */
     private void clearResultLocked() {
@@ -709,7 +642,6 @@
         mFindAccessibilityNodeInfoResult = null;
         mFindAccessibilityNodeInfosResult = null;
         mPerformAccessibilityActionResult = false;
-        mComputeClickPointResult = null;
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index b5afdf7..6096d7d 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -721,7 +721,7 @@
      * @return Whether the refresh succeeded.
      */
     public boolean refresh() {
-        return refresh(false);
+        return refresh(true);
     }
 
     /**
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index 66a3f46..cecc4af 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -54,8 +54,4 @@
     void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
         int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
         int interrogatingPid, long interrogatingTid);
-
-    void computeClickPointInScreen(long accessibilityNodeId, in Region bounds, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
-        long interrogatingTid, in MagnificationSpec spec);
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index f480216..42ae1b3 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -52,12 +52,4 @@
      * @param interactionId The interaction id to match the result with the request.
      */
     void setPerformAccessibilityActionResult(boolean succeeded, int interactionId);
-
-    /**
-     * Sets the result of a request to compute a point for clicking in a view.
-     *
-     * @param point The point of null if no such point.
-     * @param interactionId The interaction id to match the result with the request.
-     */
-    void setComputeClickPointInScreenActionResult(in Point point, int interactionId);
 }
diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java
index 2185658de3..07402b3 100644
--- a/core/java/android/webkit/WebResourceRequest.java
+++ b/core/java/android/webkit/WebResourceRequest.java
@@ -42,6 +42,8 @@
 
     /**
      * Gets whether a gesture (such as a click) was associated with the request.
+     * For security reasons in certain situations this method may return false even though the
+     * sequence of events which caused the request to be created was initiated by a user gesture.
      *
      * @return whether a gesture was associated with the request.
      */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4a7cc6d..01a506c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2387,11 +2387,14 @@
         return mProvider.getViewDelegate().shouldDelayChildPressedState();
     }
 
+    public CharSequence getAccessibilityClassName() {
+        return WebView.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(WebView.class.getName());
         mProvider.getViewDelegate().onInitializeAccessibilityNodeInfo(info);
     }
 
@@ -2399,7 +2402,6 @@
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(WebView.class.getName());
         mProvider.getViewDelegate().onInitializeAccessibilityEvent(event);
     }
 
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index d52dd60..1cc899d 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -50,7 +50,9 @@
      * is called once for each main frame load so a page with iframes or
      * framesets will call onPageStarted one time for the main frame. This also
      * means that onPageStarted will not be called when the contents of an
-     * embedded frame changes, i.e. clicking a link whose target is an iframe.
+     * embedded frame changes, i.e. clicking a link whose target is an iframe,
+     * it will also not be called for fragment navigations (navigations to
+     * #fragment_id).
      *
      * @param view The WebView that is initiating the callback.
      * @param url The url to be loaded.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7ea3265..e87a117 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -578,6 +578,12 @@
     private boolean mIsChildViewEnabled;
 
     /**
+     * The cached drawable state for the selector. Accounts for child enabled
+     * state, but otherwise identical to the view's own drawable state.
+     */
+    private int[] mSelectorState;
+
+    /**
      * The last scroll state reported to clients through {@link OnScrollListener}.
      */
     private int mLastScrollState = OnScrollListener.SCROLL_STATE_IDLE;
@@ -1486,18 +1492,15 @@
         super.sendAccessibilityEventInternal(eventType);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(AbsListView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AbsListView.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(AbsListView.class.getName());
         if (isEnabled()) {
             if (canScrollUp()) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
@@ -2789,7 +2792,7 @@
     void updateSelectorState() {
         if (mSelector != null) {
             if (shouldShowSelector()) {
-                mSelector.setState(getDrawableState());
+                mSelector.setState(getDrawableStateForSelector());
             } else {
                 mSelector.setState(StateSet.NOTHING);
             }
@@ -2802,12 +2805,11 @@
         updateSelectorState();
     }
 
-    @Override
-    protected int[] onCreateDrawableState(int extraSpace) {
+    private int[] getDrawableStateForSelector() {
         // If the child view is enabled then do the default behavior.
         if (mIsChildViewEnabled) {
             // Common case
-            return super.onCreateDrawableState(extraSpace);
+            return super.getDrawableState();
         }
 
         // The selector uses this View's drawable state. The selected child view
@@ -2815,10 +2817,12 @@
         // states.
         final int enabledState = ENABLED_STATE_SET[0];
 
-        // If we don't have any extra space, it will return one of the static state arrays,
-        // and clearing the enabled state on those arrays is a bad thing!  If we specify
-        // we need extra space, it will create+copy into a new array that safely mutable.
-        int[] state = super.onCreateDrawableState(extraSpace + 1);
+        // If we don't have any extra space, it will return one of the static
+        // state arrays, and clearing the enabled state on those arrays is a
+        // bad thing! If we specify we need extra space, it will create+copy
+        // into a new array that is safely mutable.
+        final int[] state = onCreateDrawableState(1);
+
         int enabledPos = -1;
         for (int i = state.length - 1; i >= 0; i--) {
             if (state[i] == enabledState) {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 1f7be63..78344ac 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -381,8 +381,8 @@
     }
 
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) {
-        super.onProgressRefresh(scale, fromUser);
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
+        super.onProgressRefresh(scale, fromUser, progress);
 
         final Drawable thumb = mThumb;
         if (thumb != null) {
@@ -715,18 +715,15 @@
         return super.onKeyDown(keyCode, event);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(AbsSeekBar.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AbsSeekBar.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(AbsSeekBar.class.getName());
 
         if (isEnabled()) {
             final int progress = getProgress();
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 5d8d48fd..e432747 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -470,17 +470,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(AbsSpinner.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(AbsSpinner.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AbsSpinner.class.getName();
     }
 }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 428b6ce..9b977fa 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -955,11 +955,15 @@
         return false;
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return AdapterView.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(AdapterView.class.getName());
         info.setScrollable(isScrollableForAccessibility());
         View selectedView = getSelectedView();
         if (selectedView != null) {
@@ -971,7 +975,6 @@
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(AdapterView.class.getName());
         event.setScrollable(isScrollableForAccessibility());
         View selectedView = getSelectedView();
         if (selectedView != null) {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 96eb0e2..a242175 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -1084,17 +1084,8 @@
     public void fyiWillBeAdvancedByHostKThx() {
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(AdapterViewAnimator.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(AdapterViewAnimator.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AdapterViewAnimator.class.getName();
     }
 }
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index a7ba617..01b6530 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -304,17 +304,8 @@
         updateRunning(false);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(AdapterViewFlipper.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(AdapterViewFlipper.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AdapterViewFlipper.class.getName();
     }
 }
diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java
index 90d77f9..9b0d0dd 100644
--- a/core/java/android/widget/Button.java
+++ b/core/java/android/widget/Button.java
@@ -111,17 +111,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(Button.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(Button.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Button.class.getName();
     }
 }
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index d58da8f..5e43916 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -501,16 +501,9 @@
         mDelegate.onConfigurationChanged(newConfig);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        event.setClassName(CalendarView.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        info.setClassName(CalendarView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return CalendarView.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java
index b1fb338..5a7d585 100644
--- a/core/java/android/widget/CheckBox.java
+++ b/core/java/android/widget/CheckBox.java
@@ -72,17 +72,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(CheckBox.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(CheckBox.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return CheckBox.class.getName();
     }
 }
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 477862b..344d00a 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -435,11 +435,15 @@
         }
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return CheckedTextView.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(CheckedTextView.class.getName());
         event.setChecked(mChecked);
     }
 
@@ -447,7 +451,6 @@
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(CheckedTextView.class.getName());
         info.setCheckable(true);
         info.setChecked(mChecked);
     }
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 05fc6a1..019d475 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -281,17 +281,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(Chronometer.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(Chronometer.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Chronometer.class.getName();
     }
 }
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 41a3915..fede493 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -324,11 +324,15 @@
         }
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return CompoundButton.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(CompoundButton.class.getName());
         event.setChecked(mChecked);
     }
 
@@ -336,7 +340,6 @@
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(CompoundButton.class.getName());
         info.setCheckable(true);
         info.setChecked(mChecked);
     }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 0f0cd2e..7c6055a 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -296,18 +296,9 @@
         mDelegate.onPopulateAccessibilityEvent(event);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        mDelegate.onInitializeAccessibilityEvent(event);
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        mDelegate.onInitializeAccessibilityNodeInfo(info);
+    public CharSequence getAccessibilityClassName() {
+        return DatePicker.class.getName();
     }
 
     @Override
@@ -476,8 +467,6 @@
 
         boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
         void onPopulateAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
     }
 
     /**
@@ -892,16 +881,6 @@
             event.getText().add(selectedDateUtterance);
         }
 
-        @Override
-        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-            event.setClassName(DatePicker.class.getName());
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            info.setClassName(DatePicker.class.getName());
-        }
-
         /**
          * Sets the current locale.
          *
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index a3b834e5..85b4d30 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -584,14 +584,8 @@
         event.getText().add(mCurrentDate.getTime().toString());
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(DatePicker.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(DatePicker.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return DatePicker.class.getName();
     }
 
     @Override
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index 372bdb3..b936a5b 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -115,19 +115,9 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
+    public CharSequence getAccessibilityClassName() {
         //noinspection deprecation
-        event.setClassName(DigitalClock.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        //noinspection deprecation
-        info.setClassName(DigitalClock.class.getName());
+        return DigitalClock.class.getName();
     }
 }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 6925756..391347e 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -24,7 +24,6 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.util.FloatMath;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -220,8 +219,8 @@
         if (mPullDistance == 0) {
             mGlowScaleY = mGlowScaleYStart = 0;
         } else {
-            final float scale = Math.max(0, 1 - 1 /
-                    FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
+            final float scale = (float) (Math.max(0, 1 - 1 /
+                    Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
 
             mGlowScaleY = mGlowScaleYStart = scale;
         }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index f54beb5..24cc2d8 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -122,18 +122,9 @@
         super.setEllipsize(ellipsis);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(EditText.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(EditText.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return EditText.class.getName();
     }
 
     /** @hide */
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 675dc9bb..323ddb6 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -1341,17 +1341,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ExpandableListView.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ExpandableListView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ExpandableListView.class.getName();
     }
 }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index f208fff..57bbc42 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -203,11 +204,15 @@
     }
 
     @Override
-    @RemotableViewMethod
-    public void setVisibility(@Visibility int visibility) {
-        super.setVisibility(visibility);
-        if (mForeground != null) {
-            mForeground.setVisible(visibility == VISIBLE, false);
+    protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        final Drawable dr = mForeground;
+        if (dr != null) {
+            final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
+            if (visible != dr.isVisible()) {
+                dr.setVisible(visible, false);
+            }
         }
     }
 
@@ -703,19 +708,9 @@
         return new LayoutParams(p);
     }
 
-
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(FrameLayout.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(FrameLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return FrameLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 3c428b0..ac19e6d 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1373,18 +1373,15 @@
 
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(Gallery.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Gallery.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(Gallery.class.getName());
         info.setScrollable(mItemCount > 1);
         if (isEnabled()) {
             if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index cc925ebc..41ddc98 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -1190,18 +1190,9 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(GridLayout.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(GridLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return GridLayout.class.getName();
     }
 
     // Inner classes
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f7ce57b..8b2217c 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2341,18 +2341,15 @@
         return result;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(GridView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return GridView.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(GridView.class.getName());
 
         final int columnsCount = getNumColumns();
         final int rowsCount = getCount() / columnsCount;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index f1fa1b6..b37495f 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -795,11 +795,15 @@
         return false;
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return HorizontalScrollView.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(HorizontalScrollView.class.getName());
         final int scrollRange = getScrollRange();
         if (scrollRange > 0) {
             info.setScrollable(true);
@@ -816,7 +820,6 @@
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(HorizontalScrollView.class.getName());
         event.setScrollable(getScrollRange() > 0);
         event.setScrollX(mScrollX);
         event.setScrollY(mScrollY);
diff --git a/core/java/android/widget/ImageButton.java b/core/java/android/widget/ImageButton.java
index 3b6825d..22f9c10 100644
--- a/core/java/android/widget/ImageButton.java
+++ b/core/java/android/widget/ImageButton.java
@@ -92,17 +92,8 @@
         return false;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ImageButton.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ImageButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ImageButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/ImageSwitcher.java b/core/java/android/widget/ImageSwitcher.java
index 0910eb0..80e908a 100644
--- a/core/java/android/widget/ImageSwitcher.java
+++ b/core/java/android/widget/ImageSwitcher.java
@@ -56,17 +56,8 @@
         showNext();
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ImageSwitcher.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ImageSwitcher.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ImageSwitcher.class.getName();
     }
 }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index fbad314..dd9bdb6 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -127,15 +127,16 @@
         initImageView();
     }
 
-    public ImageView(Context context, AttributeSet attrs) {
+    public ImageView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public ImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         initImageView();
@@ -1419,17 +1420,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ImageView.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ImageView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ImageView.class.getName();
     }
 }
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 28e50c4..c0f63d2 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1806,18 +1806,9 @@
         return p instanceof LinearLayout.LayoutParams;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(LinearLayout.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(LinearLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return LinearLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index df0d1fd..0aaef6d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3878,18 +3878,15 @@
         return false;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ListView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ListView.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ListView.class.getName());
 
         final int rowsCount = getCount();
         final int selectionMode = getSelectionModeForAccessibility();
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 4cafe72..0b63843 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -28,6 +28,7 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -36,8 +37,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
-import com.android.internal.policy.PolicyManager;
-
 import java.util.Formatter;
 import java.util.Locale;
 
@@ -128,7 +127,7 @@
 
     private void initFloatingWindow() {
         mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-        mWindow = PolicyManager.makeNewWindow(mContext);
+        mWindow = new PhoneWindow(mContext);
         mWindow.setWindowManager(mWindowManager, null, null);
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         mDecor = mWindow.getDecorView();
@@ -625,18 +624,9 @@
         super.setEnabled(enabled);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(MediaController.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(MediaController.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return MediaController.class.getName();
     }
 
     private View.OnClickListener mRewListener = new View.OnClickListener() {
diff --git a/core/java/android/widget/MultiAutoCompleteTextView.java b/core/java/android/widget/MultiAutoCompleteTextView.java
index 6954eea..c10e581 100644
--- a/core/java/android/widget/MultiAutoCompleteTextView.java
+++ b/core/java/android/widget/MultiAutoCompleteTextView.java
@@ -202,18 +202,9 @@
         editable.replace(start, end, mTokenizer.terminateToken(text));
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(MultiAutoCompleteTextView.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(MultiAutoCompleteTextView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return MultiAutoCompleteTextView.class.getName();
     }
 
     public static interface Tokenizer {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f5cd915..a929f3d 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -27,6 +27,11 @@
 import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
 import android.os.IBinder;
+import android.transition.Transition;
+import android.transition.Transition.EpicenterCallback;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -39,12 +44,13 @@
 import android.view.WindowManager;
 
 import java.lang.ref.WeakReference;
+import java.util.List;
 
 /**
  * <p>A popup window that can be used to display an arbitrary view. The popup
  * window is a floating container that appears on top of the current
  * activity.</p>
- * 
+ *
  * @see android.widget.AutoCompleteTextView
  * @see android.widget.Spinner
  */
@@ -56,7 +62,7 @@
      * it doesn't.
      */
     public static final int INPUT_METHOD_FROM_FOCUSABLE = 0;
-    
+
     /**
      * Mode for {@link #setInputMethodMode(int)}: this popup always needs to
      * work with an input method, regardless of whether it is focusable.  This
@@ -64,7 +70,7 @@
      * the input method while it is shown.
      */
     public static final int INPUT_METHOD_NEEDED = 1;
-    
+
     /**
      * Mode for {@link #setInputMethodMode(int)}: this popup never needs to
      * work with an input method, regardless of whether it is focusable.  This
@@ -75,14 +81,32 @@
 
     private static final int DEFAULT_ANCHORED_GRAVITY = Gravity.TOP | Gravity.START;
 
+    /**
+     * Default animation style indicating that separate animations should be
+     * used for top/bottom anchoring states.
+     */
+    private static final int ANIMATION_STYLE_DEFAULT = -1;
+
+    private final int[] mDrawingLocation = new int[2];
+    private final int[] mScreenLocation = new int[2];
+    private final Rect mTempRect = new Rect();
+    private final Rect mAnchorBounds = new Rect();
+
     private Context mContext;
     private WindowManager mWindowManager;
-    
+
     private boolean mIsShowing;
     private boolean mIsDropdown;
 
+    /** View that handles event dispatch and content transitions. */
+    private PopupDecorView mDecorView;
+
+    /** View that holds the popup background. May be the content view. */
+    private View mBackgroundView;
+
+    /** The contents of the popup. */
     private View mContentView;
-    private View mPopupView;
+
     private boolean mFocusable;
     private int mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE;
     private int mSoftInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
@@ -112,49 +136,67 @@
 
     private float mElevation;
 
-    private int[] mDrawingLocation = new int[2];
-    private int[] mScreenLocation = new int[2];
-    private Rect mTempRect = new Rect();
-    
     private Drawable mBackground;
     private Drawable mAboveAnchorBackgroundDrawable;
     private Drawable mBelowAnchorBackgroundDrawable;
 
-    // Temporary animation centers. Should be moved into window params?
-    private int mAnchorRelativeX;
-    private int mAnchorRelativeY;
+    private Transition mEnterTransition;
+    private Transition mExitTransition;
 
     private boolean mAboveAnchor;
     private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-    
+
     private OnDismissListener mOnDismissListener;
     private boolean mIgnoreCheekPress = false;
 
-    private int mAnimationStyle = -1;
-    
+    private int mAnimationStyle = ANIMATION_STYLE_DEFAULT;
+
     private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
         com.android.internal.R.attr.state_above_anchor
     };
 
     private WeakReference<View> mAnchor;
 
-    private final OnScrollChangedListener mOnScrollChangedListener =
-        new OnScrollChangedListener() {
-            @Override
-            public void onScrollChanged() {
-                final View anchor = mAnchor != null ? mAnchor.get() : null;
-                if (anchor != null && mPopupView != null) {
-                    final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                            mPopupView.getLayoutParams();
-
-                    updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
-                            mAnchoredGravity));
-                    update(p.x, p.y, -1, -1, true);
-                }
+    private final EpicenterCallback mEpicenterCallback = new EpicenterCallback() {
+        @Override
+        public Rect onGetEpicenter(Transition transition) {
+            final View anchor = mAnchor.get();
+            final View decor = mDecorView;
+            if (anchor == null || decor == null) {
+                return null;
             }
-        };
 
-    private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
+            final Rect anchorBounds = mAnchorBounds;
+            final int[] anchorLocation = mAnchor.get().getLocationOnScreen();
+            final int[] popupLocation = mDecorView.getLocationOnScreen();
+
+            // Compute the position of the anchor relative to the popup.
+            anchorBounds.set(0, 0, anchor.getWidth(), anchor.getHeight());
+            anchorBounds.offset(anchorLocation[0] - popupLocation[0],
+                    anchorLocation[1] - popupLocation[1]);
+
+            return anchorBounds;
+        }
+    };
+
+    private final OnScrollChangedListener mOnScrollChangedListener = new OnScrollChangedListener() {
+        @Override
+        public void onScrollChanged() {
+            final View anchor = mAnchor != null ? mAnchor.get() : null;
+            if (anchor != null && mDecorView != null) {
+                final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+                        mDecorView.getLayoutParams();
+
+                updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+                        mAnchoredGravity));
+                update(p.x, p.y, -1, -1, true);
+            }
+        }
+    };
+
+    private int mAnchorXoff;
+    private int mAnchorYoff;
+    private int mAnchoredGravity;
     private boolean mOverlapAnchor;
 
     private boolean mPopupViewInitialLayoutDirectionInherited;
@@ -185,10 +227,10 @@
     public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
-    
+
     /**
      * <p>Create a new, empty, non focusable popup window of dimension (0,0).</p>
-     * 
+     *
      * <p>The popup does not provide a background.</p>
      */
     public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
@@ -201,11 +243,34 @@
         mElevation = a.getDimension(R.styleable.PopupWindow_popupElevation, 0);
         mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
 
-        final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
-        mAnimationStyle = animStyle == R.style.Animation_PopupWindow ? -1 : animStyle;
+        // Preserve default behavior from Gingerbread. If the animation is
+        // undefined or explicitly specifies the Gingerbread animation style,
+        // use a sentinel value.
+        if (a.hasValueOrEmpty(R.styleable.PopupWindow_popupAnimationStyle)) {
+            final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, 0);
+            if (animStyle == R.style.Animation_PopupWindow) {
+                mAnimationStyle = ANIMATION_STYLE_DEFAULT;
+            } else {
+                mAnimationStyle = animStyle;
+            }
+        } else {
+            mAnimationStyle = ANIMATION_STYLE_DEFAULT;
+        }
+
+        final Transition enterTransition = getTransition(a.getResourceId(
+                R.styleable.PopupWindow_popupEnterTransition, 0));
+        final Transition exitTransition;
+        if (a.hasValueOrEmpty(R.styleable.PopupWindow_popupExitTransition)) {
+            exitTransition = getTransition(a.getResourceId(
+                    R.styleable.PopupWindow_popupExitTransition, 0));
+        } else {
+            exitTransition = enterTransition == null ? null : enterTransition.clone();
+        }
 
         a.recycle();
 
+        setEnterTransition(enterTransition);
+        setExitTransition(exitTransition);
         setBackgroundDrawable(bg);
     }
 
@@ -286,6 +351,37 @@
         setFocusable(focusable);
     }
 
+    public void setEnterTransition(Transition enterTransition) {
+        mEnterTransition = enterTransition;
+
+        if (mEnterTransition != null) {
+            mEnterTransition.setEpicenterCallback(mEpicenterCallback);
+        }
+    }
+
+    public void setExitTransition(Transition exitTransition) {
+        mExitTransition = exitTransition;
+
+        if (mExitTransition != null) {
+            mExitTransition.setEpicenterCallback(mEpicenterCallback);
+        }
+    }
+
+    private Transition getTransition(int resId) {
+        if (resId != 0 && resId != R.transition.no_transition) {
+            final TransitionInflater inflater = TransitionInflater.from(mContext);
+            final Transition transition = inflater.inflateTransition(resId);
+            if (transition != null) {
+                final boolean isEmpty = transition instanceof TransitionSet
+                        && ((TransitionSet) transition).getTransitionCount() == 0;
+                if (!isEmpty) {
+                    return transition;
+                }
+            }
+        }
+        return null;
+    }
+
     /**
      * Return the drawable used as the popup window's background.
      *
@@ -379,7 +475,7 @@
      * Set the flag on popup to ignore cheek press events; by default this flag
      * is set to false
      * which means the popup will not ignore cheek press dispatch events.
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
@@ -389,7 +485,7 @@
     public void setIgnoreCheekPress() {
         mIgnoreCheekPress = true;
     }
-    
+
 
     /**
      * <p>Change the animation style resource for this popup.</p>
@@ -401,13 +497,13 @@
      * @param animationStyle animation style to use when the popup appears
      *      and disappears.  Set to -1 for the default animation, 0 for no
      *      animation, or a resource identifier for an explicit animation.
-     *      
+     *
      * @see #update()
      */
     public void setAnimationStyle(int animationStyle) {
         mAnimationStyle = animationStyle;
     }
-    
+
     /**
      * <p>Return the view used as the content of the popup window.</p>
      *
@@ -491,7 +587,7 @@
      * @param focusable true if the popup should grab focus, false otherwise.
      *
      * @see #isFocusable()
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #update()
      */
     public void setFocusable(boolean focusable) {
@@ -500,23 +596,23 @@
 
     /**
      * Return the current value in {@link #setInputMethodMode(int)}.
-     * 
+     *
      * @see #setInputMethodMode(int)
      */
     public int getInputMethodMode() {
         return mInputMethodMode;
-        
+
     }
-    
+
     /**
      * Control how the popup operates with an input method: one of
      * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
      * or {@link #INPUT_METHOD_NOT_NEEDED}.
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
-     * 
+     *
      * @see #getInputMethodMode()
      * @see #update()
      */
@@ -547,12 +643,12 @@
     public int getSoftInputMode() {
         return mSoftInputMode;
     }
-    
+
     /**
      * <p>Indicates whether the popup window receives touch events.</p>
-     * 
+     *
      * @return true if the popup is touchable, false otherwise
-     * 
+     *
      * @see #setTouchable(boolean)
      */
     public boolean isTouchable() {
@@ -571,7 +667,7 @@
      * @param touchable true if the popup should receive touch events, false otherwise
      *
      * @see #isTouchable()
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #update()
      */
     public void setTouchable(boolean touchable) {
@@ -581,9 +677,9 @@
     /**
      * <p>Indicates whether the popup window will be informed of touch events
      * outside of its window.</p>
-     * 
+     *
      * @return true if the popup is outside touchable, false otherwise
-     * 
+     *
      * @see #setOutsideTouchable(boolean)
      */
     public boolean isOutsideTouchable() {
@@ -604,7 +700,7 @@
      * touch events, false otherwise
      *
      * @see #isOutsideTouchable()
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #update()
      */
     public void setOutsideTouchable(boolean touchable) {
@@ -613,9 +709,9 @@
 
     /**
      * <p>Indicates whether clipping of the popup window is enabled.</p>
-     * 
+     *
      * @return true if the clipping is enabled, false otherwise
-     * 
+     *
      * @see #setClippingEnabled(boolean)
      */
     public boolean isClippingEnabled() {
@@ -626,13 +722,13 @@
      * <p>Allows the popup window to extend beyond the bounds of the screen. By default the
      * window is clipped to the screen boundaries. Setting this to false will allow windows to be
      * accurately positioned.</p>
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
      *
      * @param enabled false if the window should be allowed to extend outside of the screen
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #isClippingEnabled()
      * @see #update()
      */
@@ -660,12 +756,12 @@
     void setAllowScrollingAnchorParent(boolean enabled) {
         mAllowScrollingAnchorParent = enabled;
     }
-    
+
     /**
      * <p>Indicates whether the popup window supports splitting touches.</p>
-     * 
+     *
      * @return true if the touch splitting is enabled, false otherwise
-     * 
+     *
      * @see #setSplitTouchEnabled(boolean)
      */
     public boolean isSplitTouchEnabled() {
@@ -794,7 +890,7 @@
      * window manager by the popup.  By default these are 0, meaning that
      * the current width or height is requested as an explicit size from
      * the window manager.  You can supply
-     * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or 
+     * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or
      * {@link ViewGroup.LayoutParams#MATCH_PARENT} to have that measure
      * spec supplied instead, replacing the absolute width and height that
      * has been set in the popup.</p>
@@ -815,7 +911,7 @@
         mWidthMode = widthSpec;
         mHeightMode = heightSpec;
     }
-    
+
     /**
      * <p>Return this popup's height MeasureSpec</p>
      *
@@ -836,7 +932,7 @@
      * @param height the height MeasureSpec of the popup
      *
      * @see #getHeight()
-     * @see #isShowing() 
+     * @see #isShowing()
      */
     public void setHeight(int height) {
         mHeight = height;
@@ -847,7 +943,7 @@
      *
      * @return the width MeasureSpec of the popup
      *
-     * @see #setWidth(int) 
+     * @see #setWidth(int)
      */
     public int getWidth() {
         return mWidth;
@@ -913,7 +1009,7 @@
      * a gravity of {@link android.view.Gravity#NO_GRAVITY} is similar to specifying
      * <code>Gravity.LEFT | Gravity.TOP</code>.
      * </p>
-     * 
+     *
      * @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
      * @param gravity the gravity which controls the placement of the popup window
      * @param x the popup's x location offset
@@ -939,23 +1035,24 @@
             return;
         }
 
+        TransitionManager.endTransitions(mDecorView);
+
         unregisterForScrollChanged();
 
         mIsShowing = true;
         mIsDropdown = false;
 
-        WindowManager.LayoutParams p = createPopupLayout(token);
-        p.windowAnimations = computeAnimationResource();
-       
+        final WindowManager.LayoutParams p = createPopupLayoutParams(token);
         preparePopup(p);
-        if (gravity == Gravity.NO_GRAVITY) {
-            gravity = Gravity.TOP | Gravity.START;
+
+        // Only override the default if some gravity was specified.
+        if (gravity != Gravity.NO_GRAVITY) {
+            p.gravity = gravity;
         }
-        p.gravity = gravity;
+
         p.x = x;
         p.y = y;
-        if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
-        if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
+
         invokePopup(p);
     }
 
@@ -1021,20 +1118,18 @@
             return;
         }
 
+        TransitionManager.endTransitions(mDecorView);
+
         registerForScrollChanged(anchor, xoff, yoff, gravity);
 
         mIsShowing = true;
         mIsDropdown = true;
 
-        WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
+        final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
         preparePopup(p);
 
-        updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
-
-        if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
-        if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
-
-        p.windowAnimations = computeAnimationResource();
+        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, gravity);
+        updateAboveAnchor(aboveAnchor);
 
         invokePopup(p);
     }
@@ -1049,12 +1144,12 @@
                 // do the job.
                 if (mAboveAnchorBackgroundDrawable != null) {
                     if (mAboveAnchor) {
-                        mPopupView.setBackground(mAboveAnchorBackgroundDrawable);
+                        mDecorView.setBackground(mAboveAnchorBackgroundDrawable);
                     } else {
-                        mPopupView.setBackground(mBelowAnchorBackgroundDrawable);
+                        mDecorView.setBackground(mBelowAnchorBackgroundDrawable);
                     }
                 } else {
-                    mPopupView.refreshDrawableState();
+                    mDecorView.refreshDrawableState();
                 }
             }
         }
@@ -1076,10 +1171,9 @@
     }
 
     /**
-     * <p>Prepare the popup by embedding in into a new ViewGroup if the
-     * background drawable is not null. If embedding is required, the layout
-     * parameters' height is modified to take into account the background's
-     * padding.</p>
+     * Prepare the popup by embedding it into a new ViewGroup if the background
+     * drawable is not null. If embedding is required, the layout parameters'
+     * height is modified to take into account the background's padding.
      *
      * @param p the layout parameters of the popup's content view
      */
@@ -1089,36 +1183,79 @@
                     + "calling setContentView() before attempting to show the popup.");
         }
 
+        // When a background is available, we embed the content view within
+        // another view that owns the background drawable.
         if (mBackground != null) {
-            final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
-            int height = ViewGroup.LayoutParams.MATCH_PARENT;
-            if (layoutParams != null &&
-                    layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
-                height = ViewGroup.LayoutParams.WRAP_CONTENT;
-            }
-
-            // when a background is available, we embed the content view
-            // within another view that owns the background drawable
-            PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
-            PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, height
-            );
-            popupViewContainer.setBackground(mBackground);
-            popupViewContainer.addView(mContentView, listParams);
-
-            mPopupView = popupViewContainer;
+            mBackgroundView = createBackgroundView(mContentView);
+            mBackgroundView.setBackground(mBackground);
         } else {
-            mPopupView = mContentView;
+            mBackgroundView = mContentView;
         }
 
-        mPopupView.setElevation(mElevation);
+        mDecorView = createDecorView(mBackgroundView);
+
+        // The background owner should be elevated so that it casts a shadow.
+        mBackgroundView.setElevation(mElevation);
+
+        // We may wrap that in another view, so we'll need to manually specify
+        // the surface insets.
+        final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
+        p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+        p.hasManualSurfaceInsets = true;
+
         mPopupViewInitialLayoutDirectionInherited =
-                (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
+                (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
         mPopupWidth = p.width;
         mPopupHeight = p.height;
     }
 
     /**
+     * Wraps a content view in a PopupViewContainer.
+     *
+     * @param contentView the content view to wrap
+     * @return a PopupViewContainer that wraps the content view
+     */
+    private PopupBackgroundView createBackgroundView(View contentView) {
+        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
+        final int height;
+        if (layoutParams != null && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            height = ViewGroup.LayoutParams.MATCH_PARENT;
+        }
+
+        final PopupBackgroundView backgroundView = new PopupBackgroundView(mContext);
+        final PopupBackgroundView.LayoutParams listParams = new PopupBackgroundView.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, height);
+        backgroundView.addView(contentView, listParams);
+
+        return backgroundView;
+    }
+
+    /**
+     * Wraps a content view in a FrameLayout.
+     *
+     * @param contentView the content view to wrap
+     * @return a FrameLayout that wraps the content view
+     */
+    private PopupDecorView createDecorView(View contentView) {
+        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
+        final int height;
+        if (layoutParams != null && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            height = ViewGroup.LayoutParams.MATCH_PARENT;
+        }
+
+        final PopupDecorView decorView = new PopupDecorView(mContext);
+        decorView.addView(contentView, ViewGroup.LayoutParams.MATCH_PARENT, height);
+        decorView.setClipChildren(false);
+        decorView.setClipToPadding(false);
+
+        return decorView;
+    }
+
+    /**
      * <p>Invoke the popup window by adding the content view to the window
      * manager.</p>
      *
@@ -1130,16 +1267,34 @@
         if (mContext != null) {
             p.packageName = mContext.getPackageName();
         }
-        mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
+
+        final View rootView = mContentView.getRootView();
+        rootView.setFitsSystemWindows(mLayoutInsetDecor);
         setLayoutDirectionFromAnchor();
-        mWindowManager.addView(mPopupView, p);
+
+        mWindowManager.addView(rootView, p);
+
+        // Postpone enter transition until the scene root has been laid out.
+        if (mEnterTransition != null) {
+            mEnterTransition.addTarget(mBackgroundView);
+            mEnterTransition.addListener(new Transition.TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    transition.removeListener(this);
+                    transition.removeTarget(mBackgroundView);
+                }
+            });
+
+            mDecorView.getViewTreeObserver().addOnGlobalLayoutListener(
+                    new PostLayoutTransitionListener(mDecorView, mEnterTransition));
+        }
     }
 
     private void setLayoutDirectionFromAnchor() {
         if (mAnchor != null) {
             View anchor = mAnchor.get();
             if (anchor != null && mPopupViewInitialLayoutDirectionInherited) {
-                mPopupView.setLayoutDirection(anchor.getLayoutDirection());
+                mDecorView.setLayoutDirection(anchor.getLayoutDirection());
             }
         }
     }
@@ -1151,26 +1306,39 @@
      *
      * @return the layout parameters to pass to the window manager
      */
-    private WindowManager.LayoutParams createPopupLayout(IBinder token) {
-        // generates the layout parameters for the drop down
-        // we want a fixed size view located at the bottom left of the anchor
-        WindowManager.LayoutParams p = new WindowManager.LayoutParams();
-        // these gravity settings put the view at the top left corner of the
-        // screen. The view is then positioned to the appropriate location
-        // by setting the x and y offsets to match the anchor's bottom
-        // left corner
+    private WindowManager.LayoutParams createPopupLayoutParams(IBinder token) {
+        final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
+
+        // These gravity settings put the view at the top left corner of the
+        // screen. The view is then positioned to the appropriate location by
+        // setting the x and y offsets to match the anchor's bottom-left
+        // corner.
         p.gravity = Gravity.START | Gravity.TOP;
-        p.width = mLastWidth = mWidth;
-        p.height = mLastHeight = mHeight;
+        p.flags = computeFlags(p.flags);
+        p.type = mWindowLayoutType;
+        p.token = token;
+        p.softInputMode = mSoftInputMode;
+        p.windowAnimations = computeAnimationResource();
+
         if (mBackground != null) {
             p.format = mBackground.getOpacity();
         } else {
             p.format = PixelFormat.TRANSLUCENT;
         }
-        p.flags = computeFlags(p.flags);
-        p.type = mWindowLayoutType;
-        p.token = token;
-        p.softInputMode = mSoftInputMode;
+
+        if (mHeightMode < 0) {
+            p.height = mLastHeight = mHeightMode;
+        } else {
+            p.height = mLastHeight = mHeight;
+        }
+
+        if (mWidthMode < 0) {
+            p.width = mLastWidth = mWidthMode;
+        } else {
+            p.width = mLastWidth = mWidth;
+        }
+
+        // Used for debugging.
         p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
 
         return p;
@@ -1224,7 +1392,7 @@
     }
 
     private int computeAnimationResource() {
-        if (mAnimationStyle == -1) {
+        if (mAnimationStyle == ANIMATION_STYLE_DEFAULT) {
             if (mIsDropdown) {
                 return mAboveAnchor
                         ? com.android.internal.R.style.Animation_DropDownUp
@@ -1243,7 +1411,7 @@
      * <p>
      * The height must have been set on the layout parameters prior to calling
      * this method.
-     * 
+     *
      * @param anchor the view on which the popup window must be anchored
      * @param p the layout parameters used to display the drop down
      * @param xoff horizontal offset used to adjust for background padding
@@ -1341,19 +1509,15 @@
 
         p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
 
-        // Compute the position of the anchor relative to the popup.
-        mAnchorRelativeX = mDrawingLocation[0] - p.x + anchorHeight / 2;
-        mAnchorRelativeY = mDrawingLocation[1] - p.y + anchorWidth / 2;
-
         return onTop;
     }
-    
+
     /**
      * Returns the maximum height that is available for the popup to be
      * completely shown. It is recommended that this height be the maximum for
      * the popup's height, otherwise it is possible that the popup will be
      * clipped.
-     * 
+     *
      * @param anchor The view on which the popup window must be anchored.
      * @return The maximum available height for the popup to be completely
      *         shown.
@@ -1376,14 +1540,14 @@
     public int getMaxAvailableHeight(View anchor, int yOffset) {
         return getMaxAvailableHeight(anchor, yOffset, false);
     }
-    
+
     /**
      * Returns the maximum height that is available for the popup to be
      * completely shown, optionally ignoring any bottom decorations such as
      * the input method. It is recommended that this height be the maximum for
      * the popup's height, otherwise it is possible that the popup will be
      * clipped.
-     * 
+     *
      * @param anchor The view on which the popup window must be anchored.
      * @param yOffset y offset from the view's bottom edge
      * @param ignoreBottomDecorations if true, the height returned will be
@@ -1391,7 +1555,7 @@
      *        bottom decorations
      * @return The maximum available height for the popup to be completely
      *         shown.
-     *         
+     *
      * @hide Pending API council approval.
      */
     public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
@@ -1400,7 +1564,7 @@
 
         final int[] anchorPos = mDrawingLocation;
         anchor.getLocationOnScreen(anchorPos);
-        
+
         int bottomEdge = displayFrame.bottom;
         if (ignoreBottomDecorations) {
             Resources res = anchor.getContext().getResources();
@@ -1413,49 +1577,83 @@
         int returnedHeight = Math.max(distanceToBottom, distanceToTop);
         if (mBackground != null) {
             mBackground.getPadding(mTempRect);
-            returnedHeight -= mTempRect.top + mTempRect.bottom; 
+            returnedHeight -= mTempRect.top + mTempRect.bottom;
         }
-        
+
         return returnedHeight;
     }
-    
+
     /**
-     * <p>Dispose of the popup window. This method can be invoked only after
-     * {@link #showAsDropDown(android.view.View)} has been executed. Failing that, calling
-     * this method will have no effect.</p>
+     * Disposes of the popup window. This method can be invoked only after
+     * {@link #showAsDropDown(android.view.View)} has been executed. Failing
+     * that, calling this method will have no effect.
      *
-     * @see #showAsDropDown(android.view.View) 
+     * @see #showAsDropDown(android.view.View)
      */
     public void dismiss() {
-        if (isShowing() && mPopupView != null) {
-            mIsShowing = false;
+        if (!isShowing()) {
+            return;
+        }
 
-            unregisterForScrollChanged();
+        unregisterForScrollChanged();
 
-            try {
-                mWindowManager.removeViewImmediate(mPopupView);
-            } finally {
-                if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
-                    ((ViewGroup) mPopupView).removeView(mContentView);
+        mIsShowing = false;
+
+        if (mExitTransition != null) {
+            // Cache the content view, since it may change without notice.
+            final View contentView = mContentView;
+
+            mExitTransition.addTarget(mBackgroundView);
+            mExitTransition.addListener(new Transition.TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    transition.removeListener(this);
+                    transition.removeTarget(mBackgroundView);
+
+                    dismissImmediate(contentView);
                 }
-                mPopupView = null;
+            });
 
-                if (mOnDismissListener != null) {
-                    mOnDismissListener.onDismiss();
-                }
+            TransitionManager.beginDelayedTransition(mDecorView, mExitTransition);
+
+            // Transition to invisible.
+            mBackgroundView.setVisibility(View.INVISIBLE);
+        } else {
+            dismissImmediate(mContentView);
+        }
+
+        if (mOnDismissListener != null) {
+            mOnDismissListener.onDismiss();
+        }
+    }
+
+    /**
+     * Removes the popup from the window manager and tears down the supporting
+     * view hierarchy, if necessary.
+     */
+    private void dismissImmediate(View contentView) {
+        try {
+            mWindowManager.removeViewImmediate(mDecorView);
+        } finally {
+            mDecorView.removeView(mBackgroundView);
+            mDecorView = null;
+
+            if (mBackgroundView != contentView) {
+                ((ViewGroup) mBackgroundView).removeView(contentView);
             }
+            mBackgroundView = null;
         }
     }
 
     /**
      * Sets the listener to be called when the window is dismissed.
-     * 
+     *
      * @param onDismissListener The listener.
      */
     public void setOnDismissListener(OnDismissListener onDismissListener) {
         mOnDismissListener = onDismissListener;
     }
-    
+
     /**
      * Updates the state of the popup window, if it is currently being displayed,
      * from the currently set state.  This includes:
@@ -1467,12 +1665,12 @@
         if (!isShowing() || mContentView == null) {
             return;
         }
-        
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                mPopupView.getLayoutParams();
-        
+
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
+
         boolean update = false;
-        
+
         final int newAnim = computeAnimationResource();
         if (newAnim != p.windowAnimations) {
             p.windowAnimations = newAnim;
@@ -1487,7 +1685,7 @@
 
         if (update) {
             setLayoutDirectionFromAnchor();
-            mWindowManager.updateViewLayout(mPopupView, p);
+            mWindowManager.updateViewLayout(mDecorView, p);
         }
     }
 
@@ -1500,11 +1698,11 @@
      * @param height the new height
      */
     public void update(int width, int height) {
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                mPopupView.getLayoutParams();
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
         update(p.x, p.y, width, height, false);
     }
-    
+
     /**
      * <p>Updates the position and the dimension of the popup window. Width and
      * height can be set to -1 to update location only.  Calling this function
@@ -1548,7 +1746,8 @@
             return;
         }
 
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
 
         boolean update = force;
 
@@ -1588,7 +1787,7 @@
 
         if (update) {
             setLayoutDirectionFromAnchor();
-            mWindowManager.updateViewLayout(mPopupView, p);
+            mWindowManager.updateViewLayout(mDecorView, p);
         }
     }
 
@@ -1655,7 +1854,7 @@
         }
 
         final WindowManager.LayoutParams p =
-                (WindowManager.LayoutParams) mPopupView.getLayoutParams();
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
         final int x = p.x;
         final int y = p.y;
         if (updateLocation) {
@@ -1679,23 +1878,22 @@
     }
 
     private void unregisterForScrollChanged() {
-        WeakReference<View> anchorRef = mAnchor;
-        View anchor = null;
-        if (anchorRef != null) {
-            anchor = anchorRef.get();
-        }
+        final WeakReference<View> anchorRef = mAnchor;
+        final View anchor = anchorRef == null ? null : anchorRef.get();
         if (anchor != null) {
-            ViewTreeObserver vto = anchor.getViewTreeObserver();
+            final ViewTreeObserver vto = anchor.getViewTreeObserver();
             vto.removeOnScrollChangedListener(mOnScrollChangedListener);
         }
+
         mAnchor = null;
     }
 
     private void registerForScrollChanged(View anchor, int xoff, int yoff, int gravity) {
         unregisterForScrollChanged();
 
-        mAnchor = new WeakReference<View>(anchor);
-        ViewTreeObserver vto = anchor.getViewTreeObserver();
+        mAnchor = new WeakReference<>(anchor);
+
+        final ViewTreeObserver vto = anchor.getViewTreeObserver();
         if (vto != null) {
             vto.addOnScrollChangedListener(mOnScrollChangedListener);
         }
@@ -1705,23 +1903,49 @@
         mAnchoredGravity = gravity;
     }
 
-    private class PopupViewContainer extends FrameLayout {
-        private static final String TAG = "PopupWindow.PopupViewContainer";
+    /**
+     * Layout listener used to run a transition immediately after a view is
+     * laid out. Forces the view to transition from invisible to visible.
+     */
+    private static class PostLayoutTransitionListener implements
+            ViewTreeObserver.OnGlobalLayoutListener {
+        private final ViewGroup mSceneRoot;
+        private final Transition mTransition;
 
-        public PopupViewContainer(Context context) {
-            super(context);
+        public PostLayoutTransitionListener(ViewGroup sceneRoot, Transition transition) {
+            mSceneRoot = sceneRoot;
+            mTransition = transition;
         }
 
         @Override
-        protected int[] onCreateDrawableState(int extraSpace) {
-            if (mAboveAnchor) {
-                // 1 more needed for the above anchor state
-                final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
-                View.mergeDrawableStates(drawableState, ABOVE_ANCHOR_STATE_SET);
-                return drawableState;
-            } else {
-                return super.onCreateDrawableState(extraSpace);
+        public void onGlobalLayout() {
+            final ViewTreeObserver observer = mSceneRoot.getViewTreeObserver();
+            if (observer == null) {
+                // View has been detached.
+                return;
             }
+
+            observer.removeOnGlobalLayoutListener(this);
+
+            // Set all targets to be initially invisible.
+            final List<View> targets = mTransition.getTargets();
+            final int N = targets.size();
+            for (int i = 0; i < N; i++) {
+                targets.get(i).setVisibility(View.INVISIBLE);
+            }
+
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+
+            // Transition targets to visible.
+            for (int i = 0; i < N; i++) {
+                targets.get(i).setVisibility(View.VISIBLE);
+            }
+        }
+    }
+
+    private class PopupDecorView extends FrameLayout {
+        public PopupDecorView(Context context) {
+            super(context);
         }
 
         @Override
@@ -1731,15 +1955,14 @@
                     return super.dispatchKeyEvent(event);
                 }
 
-                if (event.getAction() == KeyEvent.ACTION_DOWN
-                        && event.getRepeatCount() == 0) {
-                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+                    final KeyEvent.DispatcherState state = getKeyDispatcherState();
                     if (state != null) {
                         state.startTracking(event, this);
                     }
                     return true;
                 } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                    final KeyEvent.DispatcherState state = getKeyDispatcherState();
                     if (state != null && state.isTracking(event) && !event.isCanceled()) {
                         dismiss();
                         return true;
@@ -1763,7 +1986,7 @@
         public boolean onTouchEvent(MotionEvent event) {
             final int x = (int) event.getX();
             final int y = (int) event.getY();
-            
+
             if ((event.getAction() == MotionEvent.ACTION_DOWN)
                     && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
                 dismiss();
@@ -1775,17 +1998,22 @@
                 return super.onTouchEvent(event);
             }
         }
+    }
 
-    /** @hide */
+    private class PopupBackgroundView extends FrameLayout {
+        public PopupBackgroundView(Context context) {
+            super(context);
+        }
+
         @Override
-        public void sendAccessibilityEventInternal(int eventType) {
-            // clinets are interested in the content not the container, make it event source
-            if (mContentView != null) {
-                mContentView.sendAccessibilityEvent(eventType);
+        protected int[] onCreateDrawableState(int extraSpace) {
+            if (mAboveAnchor) {
+                final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+                View.mergeDrawableStates(drawableState, ABOVE_ANCHOR_STATE_SET);
+                return drawableState;
             } else {
-                super.sendAccessibilityEventInternal(eventType);
+                return super.onCreateDrawableState(extraSpace);
             }
         }
     }
-    
 }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index d32cb10..5b0745e 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.graphics.PorterDuff;
+
 import com.android.internal.R;
 
 import android.content.Context;
@@ -64,8 +65,8 @@
 /**
  * <p>
  * Visual indicator of progress in some operation.  Displays a bar to the user
- * representing how far the operation has progressed; the application can 
- * change the amount of progress (modifying the length of the bar) as it moves 
+ * representing how far the operation has progressed; the application can
+ * change the amount of progress (modifying the length of the bar) as it moves
  * forward.  There is also a secondary progress displayable on a progress bar
  * which is useful for displaying intermediate progress, such as the buffer
  * level during a streaming playback progress bar.
@@ -81,7 +82,7 @@
  * <p>The following code example shows how a progress bar can be used from
  * a worker thread to update the user interface to notify the user of progress:
  * </p>
- * 
+ *
  * <pre>
  * public class MyActivity extends Activity {
  *     private static final int PROGRESS = 0x1;
@@ -169,13 +170,13 @@
  * </ul>
  * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
  * if your application uses a light colored theme (a white background).</p>
- *  
- * <p><strong>XML attributes</b></strong> 
- * <p> 
- * See {@link android.R.styleable#ProgressBar ProgressBar Attributes}, 
+ *
+ * <p><strong>XML attributes</b></strong>
+ * <p>
+ * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
  * {@link android.R.styleable#View View Attributes}
  * </p>
- * 
+ *
  * @attr ref android.R.styleable#ProgressBar_animationResolution
  * @attr ref android.R.styleable#ProgressBar_indeterminate
  * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
@@ -244,7 +245,7 @@
     public ProgressBar(Context context) {
         this(context, null);
     }
-    
+
     public ProgressBar(Context context, AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.progressBarStyle);
     }
@@ -261,9 +262,9 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
-        
+
         mNoInvalidate = true;
-        
+
         final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
         if (progressDrawable != null) {
             // Calling this method can set mMaxHeight, make sure the corresponding
@@ -282,11 +283,11 @@
         mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
 
         final int resID = a.getResourceId(
-                com.android.internal.R.styleable.ProgressBar_interpolator, 
+                com.android.internal.R.styleable.ProgressBar_interpolator,
                 android.R.anim.linear_interpolator); // default to linear interpolator
         if (resID > 0) {
             setInterpolator(context, resID);
-        } 
+        }
 
         setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
 
@@ -399,12 +400,12 @@
      * traverse layer and state list drawables.
      */
     private Drawable tileify(Drawable drawable, boolean clip) {
-        
+
         if (drawable instanceof LayerDrawable) {
             LayerDrawable background = (LayerDrawable) drawable;
             final int N = background.getNumberOfLayers();
             Drawable[] outDrawables = new Drawable[N];
-            
+
             for (int i = 0; i < N; i++) {
                 int id = background.getId(i);
                 outDrawables[i] = tileify(background.getDrawable(i),
@@ -412,13 +413,13 @@
             }
 
             LayerDrawable newBg = new LayerDrawable(outDrawables);
-            
+
             for (int i = 0; i < N; i++) {
                 newBg.setId(i, background.getId(i));
             }
-            
+
             return newBg;
-            
+
         } else if (drawable instanceof StateListDrawable) {
             StateListDrawable in = (StateListDrawable) drawable;
             StateListDrawable out = new StateListDrawable();
@@ -427,7 +428,7 @@
                 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
             }
             return out;
-            
+
         } else if (drawable instanceof BitmapDrawable) {
             final BitmapDrawable bitmap = (BitmapDrawable) drawable;
             final Bitmap tileBitmap = bitmap.getBitmap();
@@ -448,7 +449,7 @@
             return clip ? new ClipDrawable(
                     shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable;
         }
-        
+
         return drawable;
     }
 
@@ -456,7 +457,7 @@
         final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
         return new RoundRectShape(roundedCorners, null, null);
     }
-    
+
     /**
      * Convert a AnimationDrawable for use as a barberpole animation.
      * Each frame of the animation is wrapped in a ClipDrawable and
@@ -468,7 +469,7 @@
             final int N = background.getNumberOfFrames();
             AnimationDrawable newBg = new AnimationDrawable();
             newBg.setOneShot(background.isOneShot());
-            
+
             for (int i = 0; i < N; i++) {
                 Drawable frame = tileify(background.getFrame(i), true);
                 frame.setLevel(10000);
@@ -479,7 +480,7 @@
         }
         return drawable;
     }
-    
+
     /**
      * <p>
      * Initialize the progress bar's default values:
@@ -520,7 +521,7 @@
      * <p>Change the indeterminate mode for this progress bar. In indeterminate
      * mode, the progress is ignored and the progress bar shows an infinite
      * animation instead.</p>
-     * 
+     *
      * If this progress bar's style only supports indeterminate mode (such as the circular
      * progress bars), then this will be ignored.
      *
@@ -699,7 +700,7 @@
 
         setIndeterminateDrawable(d);
     }
-    
+
     /**
      * <p>Get the drawable used to draw the progress bar in
      * progress mode.</p>
@@ -1135,7 +1136,7 @@
 
         setProgressDrawable(d);
     }
-    
+
     /**
      * @return The drawable currently used to draw the progress bar
      */
@@ -1214,7 +1215,7 @@
             rd.fromUser = fromUser;
             return rd;
         }
-        
+
         public void recycle() {
             sPool.release(this);
         }
@@ -1257,13 +1258,13 @@
         } else {
             invalidate();
         }
-        
+
         if (callBackToApp && id == R.id.progress) {
-            onProgressRefresh(scale, fromUser);
+            onProgressRefresh(scale, fromUser, progress);
         }
     }
 
-    void onProgressRefresh(float scale, boolean fromUser) {
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             scheduleAccessibilityEventSender();
         }
@@ -1285,7 +1286,7 @@
             }
         }
     }
-    
+
     /**
      * <p>Set the current progress to the specified value. Does not do anything
      * if the progress bar is in indeterminate mode.</p>
@@ -1295,13 +1296,13 @@
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
      * @see #getProgress()
-     * @see #incrementProgressBy(int) 
+     * @see #incrementProgressBy(int)
      */
     @android.view.RemotableViewMethod
     public synchronized void setProgress(int progress) {
         setProgress(progress, false);
     }
-    
+
     @android.view.RemotableViewMethod
     synchronized void setProgress(int progress, boolean fromUser) {
         if (mIndeterminate) {
@@ -1327,7 +1328,7 @@
      * Set the current secondary progress to the specified value. Does not do
      * anything if the progress bar is in indeterminate mode.
      * </p>
-     * 
+     *
      * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
@@ -1408,8 +1409,8 @@
      * @param max the upper range of this progress bar
      *
      * @see #getMax()
-     * @see #setProgress(int) 
-     * @see #setSecondaryProgress(int) 
+     * @see #setProgress(int)
+     * @see #setSecondaryProgress(int)
      */
     @android.view.RemotableViewMethod
     public synchronized void setMax(int max) {
@@ -1426,13 +1427,13 @@
             refreshProgress(R.id.progress, mProgress, false);
         }
     }
-    
+
     /**
      * <p>Increase the progress bar's progress by the specified amount.</p>
      *
      * @param diff the amount by which the progress must be increased
      *
-     * @see #setProgress(int) 
+     * @see #setProgress(int)
      */
     public synchronized final void incrementProgressBy(int diff) {
         setProgress(mProgress + diff);
@@ -1443,7 +1444,7 @@
      *
      * @param diff the amount by which the secondary progress must be increased
      *
-     * @see #setSecondaryProgress(int) 
+     * @see #setSecondaryProgress(int)
      */
     public synchronized final void incrementSecondaryProgressBy(int diff) {
         setSecondaryProgress(mSecondaryProgress + diff);
@@ -1466,13 +1467,13 @@
             if (mInterpolator == null) {
                 mInterpolator = new LinearInterpolator();
             }
-    
+
             if (mTransformation == null) {
                 mTransformation = new Transformation();
             } else {
                 mTransformation.clear();
             }
-            
+
             if (mAnimation == null) {
                 mAnimation = new AlphaAnimation(0.0f, 1.0f);
             } else {
@@ -1623,7 +1624,7 @@
             }
             mIndeterminateDrawable.setBounds(left, top, right, bottom);
         }
-        
+
         if (mProgressDrawable != null) {
             mProgressDrawable.setBounds(0, 0, right, bottom);
         }
@@ -1693,20 +1694,20 @@
         setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
                 resolveSizeAndState(dh, heightMeasureSpec, 0));
     }
-    
+
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
         updateDrawableState();
     }
-        
+
     private void updateDrawableState() {
         int[] state = getDrawableState();
-        
+
         if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
             mProgressDrawable.setState(state);
         }
-        
+
         if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
             mIndeterminateDrawable.setState(state);
         }
@@ -1728,14 +1729,14 @@
     static class SavedState extends BaseSavedState {
         int progress;
         int secondaryProgress;
-        
+
         /**
          * Constructor called from {@link ProgressBar#onSaveInstanceState()}
          */
         SavedState(Parcelable superState) {
             super(superState);
         }
-        
+
         /**
          * Constructor called from {@link #CREATOR}
          */
@@ -1769,10 +1770,10 @@
         // Force our ancestor class to save its state
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        
+
         ss.progress = mProgress;
         ss.secondaryProgress = mSecondaryProgress;
-        
+
         return ss;
     }
 
@@ -1780,7 +1781,7 @@
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        
+
         setProgress(ss.progress);
         setSecondaryProgress(ss.secondaryProgress);
     }
@@ -1825,20 +1826,17 @@
         mAttached = false;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ProgressBar.class.getName());
-        event.setItemCount(mMax);
-        event.setCurrentItemIndex(mProgress);
+    public CharSequence getAccessibilityClassName() {
+        return ProgressBar.class.getName();
     }
 
     /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ProgressBar.class.getName());
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
+        event.setItemCount(mMax);
+        event.setCurrentItemIndex(mProgress);
     }
 
     /**
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index d0e8081..3068de9 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -304,18 +304,9 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(QuickContactBadge.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(QuickContactBadge.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return QuickContactBadge.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/RadioButton.java b/core/java/android/widget/RadioButton.java
index 82280b4..aebc1b6 100644
--- a/core/java/android/widget/RadioButton.java
+++ b/core/java/android/widget/RadioButton.java
@@ -79,17 +79,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(RadioButton.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(RadioButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RadioButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index c0f60eb..f04bb3d 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -240,18 +240,9 @@
         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(RadioGroup.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(RadioGroup.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RadioGroup.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 2d0649d..f18e372 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -43,7 +43,7 @@
  * <p>
  * The secondary progress should not be modified by the client as it is used
  * internally as the background for a fractionally filled star.
- * 
+ *
  * @attr ref android.R.styleable#RatingBar_numStars
  * @attr ref android.R.styleable#RatingBar_rating
  * @attr ref android.R.styleable#RatingBar_stepSize
@@ -58,14 +58,14 @@
      * programmatically.
      */
     public interface OnRatingBarChangeListener {
-        
+
         /**
          * Notification that the rating has changed. Clients can use the
          * fromUser parameter to distinguish user-initiated changes from those
          * that occurred programmatically. This will not be called continuously
          * while the user is dragging, only when the user finalizes a rating by
          * lifting the touch.
-         * 
+         *
          * @param ratingBar The RatingBar whose rating has changed.
          * @param rating The current rating. This will be in the range
          *            0..numStars.
@@ -79,9 +79,9 @@
     private int mNumStars = 5;
 
     private int mProgressOnStartTracking;
-    
+
     private OnRatingBarChangeListener mOnRatingBarChangeListener;
-    
+
     public RatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
@@ -98,19 +98,19 @@
         a.recycle();
 
         if (numStars > 0 && numStars != mNumStars) {
-            setNumStars(numStars);            
+            setNumStars(numStars);
         }
-        
+
         if (stepSize >= 0) {
             setStepSize(stepSize);
         } else {
             setStepSize(0.5f);
         }
-        
+
         if (rating >= 0) {
             setRating(rating);
         }
-        
+
         // A touch inside a star fill up to that fractional area (slightly more
         // than 1 so boundaries round up).
         mTouchProgressOffset = 1.1f;
@@ -123,16 +123,16 @@
     public RatingBar(Context context) {
         this(context, null);
     }
-    
+
     /**
      * Sets the listener to be called when the rating changes.
-     * 
+     *
      * @param listener The listener.
      */
     public void setOnRatingBarChangeListener(OnRatingBarChangeListener listener) {
         mOnRatingBarChangeListener = listener;
     }
-    
+
     /**
      * @return The listener (may be null) that is listening for rating change
      *         events.
@@ -144,7 +144,7 @@
     /**
      * Whether this rating bar should only be an indicator (thus non-changeable
      * by the user).
-     * 
+     *
      * @param isIndicator Whether it should be an indicator.
      *
      * @attr ref android.R.styleable#RatingBar_isIndicator
@@ -153,7 +153,7 @@
         mIsUserSeekable = !isIndicator;
         setFocusable(!isIndicator);
     }
-    
+
     /**
      * @return Whether this rating bar is only an indicator.
      *
@@ -162,21 +162,21 @@
     public boolean isIndicator() {
         return !mIsUserSeekable;
     }
-    
+
     /**
      * Sets the number of stars to show. In order for these to be shown
      * properly, it is recommended the layout width of this widget be wrap
      * content.
-     * 
+     *
      * @param numStars The number of stars.
      */
     public void setNumStars(final int numStars) {
         if (numStars <= 0) {
             return;
         }
-        
+
         mNumStars = numStars;
-        
+
         // This causes the width to change, so re-layout
         requestLayout();
     }
@@ -188,10 +188,10 @@
     public int getNumStars() {
         return mNumStars;
     }
-    
+
     /**
      * Sets the rating (the number of stars filled).
-     * 
+     *
      * @param rating The rating to set.
      */
     public void setRating(float rating) {
@@ -200,16 +200,16 @@
 
     /**
      * Gets the current rating (number of stars filled).
-     * 
+     *
      * @return The current rating.
      */
     public float getRating() {
-        return getProgress() / getProgressPerStar();        
+        return getProgress() / getProgressPerStar();
     }
 
     /**
      * Sets the step size (granularity) of this rating bar.
-     * 
+     *
      * @param stepSize The step size of this rating bar. For example, if
      *            half-star granularity is wanted, this would be 0.5.
      */
@@ -217,7 +217,7 @@
         if (stepSize <= 0) {
             return;
         }
-        
+
         final float newMax = mNumStars / stepSize;
         final int newProgress = (int) (newMax / getMax() * getProgress());
         setMax((int) newMax);
@@ -226,13 +226,13 @@
 
     /**
      * Gets the step size of this rating bar.
-     * 
+     *
      * @return The step size.
      */
     public float getStepSize() {
         return (float) getNumStars() / getMax();
     }
-    
+
     /**
      * @return The amount of progress that fits into a star
      */
@@ -251,12 +251,12 @@
     }
 
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) {
-        super.onProgressRefresh(scale, fromUser);
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
+        super.onProgressRefresh(scale, fromUser, progress);
 
         // Keep secondary progress in sync with primary
-        updateSecondaryProgress(getProgress());
-        
+        updateSecondaryProgress(progress);
+
         if (!fromUser) {
             // Callback for non-user rating changes
             dispatchRatingChange(false);
@@ -267,7 +267,7 @@
      * The secondary progress is used to differentiate the background of a
      * partially filled star. This method keeps the secondary progress in sync
      * with the progress.
-     * 
+     *
      * @param progress The primary progress level.
      */
     private void updateSecondaryProgress(int progress) {
@@ -278,11 +278,11 @@
             setSecondaryProgress(secondaryProgress);
         }
     }
-    
+
     @Override
     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        
+
         if (mSampleTile != null) {
             // TODO: Once ProgressBar's TODOs are gone, this can be done more
             // cleanly than mSampleTile
@@ -295,7 +295,7 @@
     @Override
     void onStartTrackingTouch() {
         mProgressOnStartTracking = getProgress();
-        
+
         super.onStartTrackingTouch();
     }
 
@@ -327,21 +327,12 @@
         if (max <= 0) {
             return;
         }
-        
+
         super.setMax(max);
     }
-    
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(RatingBar.class.getName());
-    }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(RatingBar.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RatingBar.class.getName();
     }
 }
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 71f4da0..89b1d54 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1103,18 +1103,9 @@
         return false;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(RelativeLayout.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(RelativeLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RelativeLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index b12c581..6fd90c3 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -44,6 +44,7 @@
     private boolean mRangeChanged;
     private boolean mAlwaysDrawHorizontalTrack;
     private boolean mAlwaysDrawVerticalTrack;
+    private boolean mMutated;
 
     private int mAlpha = 255;
     private boolean mHasSetAlpha;
@@ -266,6 +267,10 @@
 
     private void propagateCurrentState(Drawable d) {
         if (d != null) {
+            if (mMutated) {
+                d.mutate();
+            }
+
             d.setState(getState());
             d.setCallback(this);
 
@@ -290,6 +295,26 @@
     }
 
     @Override
+    public ScrollBarDrawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            if (mVerticalTrack != null) {
+                mVerticalTrack.mutate();
+            }
+            if (mVerticalThumb != null) {
+                mVerticalThumb.mutate();
+            }
+            if (mHorizontalTrack != null) {
+                mHorizontalTrack.mutate();
+            }
+            if (mHorizontalThumb != null) {
+                mHorizontalThumb.mutate();
+            }
+            mMutated = true;
+        }
+        return this;
+    }
+
+    @Override
     public void setAlpha(int alpha) {
         mAlpha = alpha;
         mHasSetAlpha = true;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 1098419..b95c27d 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -839,11 +839,15 @@
         return false;
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return ScrollView.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ScrollView.class.getName());
         if (isEnabled()) {
             final int scrollRange = getScrollRange();
             if (scrollRange > 0) {
@@ -862,7 +866,6 @@
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ScrollView.class.getName());
         final boolean scrollable = getScrollRange() > 0;
         event.setScrollable(scrollable);
         event.setScrollX(mScrollX);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index a1f361a..8846421 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1325,18 +1325,9 @@
         setIconified(false);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(SearchView.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(SearchView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return SearchView.class.getName();
     }
 
     private void adjustDropDownSizeAndPosition() {
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index aa5c055..fc070e7 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -26,7 +26,7 @@
 /**
  * A SeekBar is an extension of ProgressBar that adds a draggable thumb. The user can touch
  * the thumb and drag left or right to set the current progress level or use the arrow keys.
- * Placing focusable widgets to the left or right of a SeekBar is discouraged. 
+ * Placing focusable widgets to the left or right of a SeekBar is discouraged.
  * <p>
  * Clients of the SeekBar can attach a {@link SeekBar.OnSeekBarChangeListener} to
  * be notified of the user's actions.
@@ -42,39 +42,39 @@
      * programmatically.
      */
     public interface OnSeekBarChangeListener {
-        
+
         /**
          * Notification that the progress level has changed. Clients can use the fromUser parameter
          * to distinguish user-initiated changes from those that occurred programmatically.
-         * 
+         *
          * @param seekBar The SeekBar whose progress has changed
          * @param progress The current progress level. This will be in the range 0..max where max
          *        was set by {@link ProgressBar#setMax(int)}. (The default value for max is 100.)
          * @param fromUser True if the progress change was initiated by the user.
          */
         void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser);
-    
+
         /**
          * Notification that the user has started a touch gesture. Clients may want to use this
-         * to disable advancing the seekbar. 
+         * to disable advancing the seekbar.
          * @param seekBar The SeekBar in which the touch gesture began
          */
         void onStartTrackingTouch(SeekBar seekBar);
-        
+
         /**
          * Notification that the user has finished a touch gesture. Clients may want to use this
-         * to re-enable advancing the seekbar. 
+         * to re-enable advancing the seekbar.
          * @param seekBar The SeekBar in which the touch gesture began
          */
         void onStopTrackingTouch(SeekBar seekBar);
     }
 
     private OnSeekBarChangeListener mOnSeekBarChangeListener;
-    
+
     public SeekBar(Context context) {
         this(context, null);
     }
-    
+
     public SeekBar(Context context, AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.seekBarStyle);
     }
@@ -88,26 +88,26 @@
     }
 
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) {
-        super.onProgressRefresh(scale, fromUser);
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
+        super.onProgressRefresh(scale, fromUser, progress);
 
         if (mOnSeekBarChangeListener != null) {
-            mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
+            mOnSeekBarChangeListener.onProgressChanged(this, progress, fromUser);
         }
     }
 
     /**
      * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
      * provides notifications of when the user starts and stops a touch gesture within the SeekBar.
-     * 
+     *
      * @param l The seek bar notification listener
-     * 
+     *
      * @see SeekBar.OnSeekBarChangeListener
      */
     public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
         mOnSeekBarChangeListener = l;
     }
-    
+
     @Override
     void onStartTrackingTouch() {
         super.onStartTrackingTouch();
@@ -115,7 +115,7 @@
             mOnSeekBarChangeListener.onStartTrackingTouch(this);
         }
     }
-    
+
     @Override
     void onStopTrackingTouch() {
         super.onStopTrackingTouch();
@@ -124,17 +124,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(SeekBar.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(SeekBar.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return SeekBar.class.getName();
     }
 }
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index e3f4a10..272f4b0 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -837,18 +837,9 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(SlidingDrawer.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(SlidingDrawer.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return SlidingDrawer.class.getName();
     }
 
     private void closeDrawer() {
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index a6e0e6d..6ee2b4c 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -765,18 +765,15 @@
         dialog.dismiss();
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(Spinner.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Spinner.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(Spinner.class.getName());
 
         if (mAdapter != null) {
             info.setCanOpenPopup(true);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 2aa1c09..803ba4b 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1224,18 +1224,15 @@
         measureChildren();
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(StackView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return StackView.class.getName();
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(StackView.class.getName());
         info.setScrollable(getChildCount() > 1);
         if (isEnabled()) {
             if (getDisplayedChild() < getChildCount() - 1) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 13d6b42..b959ddc 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -24,10 +25,12 @@
 import android.graphics.Canvas;
 import android.graphics.Insets;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -41,6 +44,7 @@
 import android.view.MotionEvent;
 import android.view.SoundEffectConstants;
 import android.view.VelocityTracker;
+import android.view.ViewAssistData;
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -84,7 +88,17 @@
     private static final int MONOSPACE = 3;
 
     private Drawable mThumbDrawable;
+    private ColorStateList mThumbTintList = null;
+    private PorterDuff.Mode mThumbTintMode = null;
+    private boolean mHasThumbTint = false;
+    private boolean mHasThumbTintMode = false;
+
     private Drawable mTrackDrawable;
+    private ColorStateList mTrackTintList = null;
+    private PorterDuff.Mode mTrackTintMode = null;
+    private boolean mHasTrackTint = false;
+    private boolean mHasTrackTintMode = false;
+
     private int mThumbTextPadding;
     private int mSwitchMinWidth;
     private int mSwitchPadding;
@@ -473,6 +487,86 @@
     }
 
     /**
+     * Applies a tint to the track drawable. Does not modify the current
+     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setTrackDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Switch_trackTint
+     * @see #getTrackTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public void setTrackTintList(@Nullable ColorStateList tint) {
+        mTrackTintList = tint;
+        mHasTrackTint = true;
+
+        applyTrackTint();
+    }
+
+    /**
+     * @return the tint applied to the track drawable
+     * @attr ref android.R.styleable#Switch_trackTint
+     * @see #setTrackTintList(ColorStateList)
+     */
+    @Nullable
+    public ColorStateList getTrackTintList() {
+        return mTrackTintList;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setTrackTintList(ColorStateList)}} to the track drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#Switch_trackTintMode
+     * @see #getTrackTintMode()
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public void setTrackTintMode(@Nullable PorterDuff.Mode tintMode) {
+        mTrackTintMode = tintMode;
+        mHasTrackTintMode = true;
+
+        applyTrackTint();
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the track
+     *         drawable
+     * @attr ref android.R.styleable#Switch_trackTintMode
+     * @see #setTrackTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getTrackTintMode() {
+        return mTrackTintMode;
+    }
+
+    private void applyTrackTint() {
+        if (mTrackDrawable != null && (mHasTrackTint || mHasTrackTintMode)) {
+            mTrackDrawable = mTrackDrawable.mutate();
+
+            if (mHasTrackTint) {
+                mTrackDrawable.setTintList(mTrackTintList);
+            }
+
+            if (mHasTrackTintMode) {
+                mTrackDrawable.setTintMode(mTrackTintMode);
+            }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mTrackDrawable.isStateful()) {
+                mTrackDrawable.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Set the drawable used for the switch "thumb" - the piece that the user
      * can physically touch and drag along the track.
      *
@@ -516,6 +610,86 @@
     }
 
     /**
+     * Applies a tint to the thumb drawable. Does not modify the current
+     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setThumbDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Switch_thumbTint
+     * @see #getThumbTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public void setThumbTintList(@Nullable ColorStateList tint) {
+        mThumbTintList = tint;
+        mHasThumbTint = true;
+
+        applyThumbTint();
+    }
+
+    /**
+     * @return the tint applied to the thumb drawable
+     * @attr ref android.R.styleable#Switch_thumbTint
+     * @see #setThumbTintList(ColorStateList)
+     */
+    @Nullable
+    public ColorStateList getThumbTintList() {
+        return mThumbTintList;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#Switch_thumbTintMode
+     * @see #getThumbTintMode()
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
+        mThumbTintMode = tintMode;
+        mHasThumbTintMode = true;
+
+        applyThumbTint();
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the thumb
+     *         drawable
+     * @attr ref android.R.styleable#Switch_thumbTintMode
+     * @see #setThumbTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getThumbTintMode() {
+        return mThumbTintMode;
+    }
+
+    private void applyThumbTint() {
+        if (mThumbDrawable != null && (mHasThumbTint || mHasThumbTintMode)) {
+            mThumbDrawable = mThumbDrawable.mutate();
+
+            if (mHasThumbTint) {
+                mThumbDrawable.setTintList(mThumbTintList);
+            }
+
+            if (mHasThumbTintMode) {
+                mThumbDrawable.setTintMode(mThumbTintMode);
+            }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mThumbDrawable.isStateful()) {
+                mThumbDrawable.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Specifies whether the track should be split by the thumb. When true,
      * the thumb's optical bounds will be clipped out of the track drawable,
      * then the thumb will be drawn into the resulting gap.
@@ -1181,18 +1355,31 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(Switch.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Switch.class.getName();
+    }
+
+    @Override
+    public void onProvideAssistData(ViewAssistData data, Bundle extras) {
+        super.onProvideAssistData(data, extras);
+        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
+        if (!TextUtils.isEmpty(switchText)) {
+            CharSequence oldText = data.getText();
+            if (TextUtils.isEmpty(oldText)) {
+                data.setText(switchText);
+            } else {
+                StringBuilder newText = new StringBuilder();
+                newText.append(oldText).append(' ').append(switchText);
+                data.setText(newText);
+            }
+        }
     }
 
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(Switch.class.getName());
         CharSequence switchText = isChecked() ? mTextOn : mTextOff;
         if (!TextUtils.isEmpty(switchText)) {
             CharSequence oldText = info.getText();
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 3c3389a..bf35cf9 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -384,18 +384,9 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(TabHost.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(TabHost.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TabHost.class.getName();
     }
 
     public void setCurrentTab(int index) {
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index bddee91..88ecb13 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -415,11 +415,15 @@
         return false;
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return TabWidget.class.getName();
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(TabWidget.class.getName());
         event.setItemCount(getTabCount());
         event.setCurrentItemIndex(mSelectedTab);
     }
@@ -436,13 +440,6 @@
         super.sendAccessibilityEventUncheckedInternal(event);
     }
 
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(TabWidget.class.getName());
-    }
-
     /**
      * Sets the current tab and focuses the UI on it.
      * This method makes sure that the focused tab matches the selected
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index a6b78a4..c825d17 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -666,18 +666,9 @@
         return new LayoutParams(p);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(TableLayout.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(TableLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TableLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index c29296a..72fce3f 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -379,18 +379,9 @@
         return new LayoutParams(p);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(TableRow.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(TableRow.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TableRow.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/TextSwitcher.java b/core/java/android/widget/TextSwitcher.java
index 7c883ba..22822b1 100644
--- a/core/java/android/widget/TextSwitcher.java
+++ b/core/java/android/widget/TextSwitcher.java
@@ -91,17 +91,8 @@
         ((TextView)getCurrentView()).setText(text);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(TextSwitcher.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(TextSwitcher.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TextSwitcher.class.getName();
     }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e8bf623..848c1c0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -109,6 +109,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewAssistData;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
 import android.view.ViewGroup.LayoutParams;
@@ -665,6 +666,7 @@
         ColorStateList textColorLink = null;
         int textSize = 15;
         String fontFamily = null;
+        boolean fontFamilyExplicit = false;
         int typefaceIndex = -1;
         int styleIndex = -1;
         boolean allCaps = false;
@@ -1029,6 +1031,7 @@
 
             case com.android.internal.R.styleable.TextView_fontFamily:
                 fontFamily = a.getString(attr);
+                fontFamilyExplicit = true;
                 break;
 
             case com.android.internal.R.styleable.TextView_password:
@@ -1333,6 +1336,9 @@
             typefaceIndex = MONOSPACE;
         }
 
+        if (typefaceIndex != -1 && !fontFamilyExplicit) {
+            fontFamily = null;
+        }
         setTypefaceFromAttrs(fontFamily, typefaceIndex, styleIndex);
 
         if (shadowcolor != 0) {
@@ -8526,12 +8532,26 @@
                 UserHandle.USER_CURRENT_OR_SELF) == 1);
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return TextView.class.getName();
+    }
+
+    @Override
+    public void onProvideAssistData(ViewAssistData data, Bundle extras) {
+        super.onProvideAssistData(data, extras);
+        final boolean isPassword = hasPasswordTransformationMethod();
+        if (!isPassword) {
+            data.setText(getText(), getSelectionStart(), getSelectionEnd());
+        }
+        data.setHint(getHint());
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
 
-        event.setClassName(TextView.class.getName());
         final boolean isPassword = hasPasswordTransformationMethod();
         event.setPassword(isPassword);
 
@@ -8547,7 +8567,6 @@
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
 
-        info.setClassName(TextView.class.getName());
         final boolean isPassword = hasPasswordTransformationMethod();
         info.setPassword(isPassword);
 
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index bbf5f53..9df8a21 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -195,33 +195,17 @@
         mDelegate.onRestoreInstanceState(ss);
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return TimePicker.class.getName();
+    }
+
     /** @hide */
     @Override
     public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         return mDelegate.dispatchPopulateAccessibilityEvent(event);
     }
 
-    /** @hide */
-    @Override
-    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEventInternal(event);
-        mDelegate.onPopulateAccessibilityEvent(event);
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        mDelegate.onInitializeAccessibilityEvent(event);
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        mDelegate.onInitializeAccessibilityNodeInfo(info);
-    }
-
     /**
      * A delegate interface that defined the public API of the TimePicker. Allows different
      * TimePicker implementations. This would need to be implemented by the TimePicker delegates
@@ -252,8 +236,6 @@
 
         boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
         void onPopulateAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
     }
 
     /**
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1534429..05c7a5f 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -466,16 +466,6 @@
         event.getText().add(selectedDate);
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(TimePicker.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(TimePicker.class.getName());
-    }
-
     /**
      * Set whether in keyboard mode or not.
      *
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index e162f4a..af69110 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -427,16 +427,6 @@
         event.getText().add(selectedDateUtterance);
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(TimePicker.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(TimePicker.class.getName());
-    }
-
     private void updateInputState() {
         // Make sure that if the user changes the value and the IME is active
         // for one of the inputs if this widget, the IME is closed. If the user
diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java
index 1b23778..4f8342b 100644
--- a/core/java/android/widget/ToggleButton.java
+++ b/core/java/android/widget/ToggleButton.java
@@ -153,17 +153,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ToggleButton.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ToggleButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ToggleButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java
index 9035dbe..0cd7eb9 100644
--- a/core/java/android/widget/TwoLineListItem.java
+++ b/core/java/android/widget/TwoLineListItem.java
@@ -93,17 +93,8 @@
         return mText2;
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(TwoLineListItem.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(TwoLineListItem.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TwoLineListItem.class.getName();
     }
 }
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index a240dc2..48283d4 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -201,18 +201,9 @@
         setMeasuredDimension(width, height);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(VideoView.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(VideoView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return VideoView.class.getName();
     }
 
     public int resolveAdjustedSize(int desiredSize, int measureSpec) {
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index d31754b..5ef5222 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -357,17 +357,8 @@
         return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ViewAnimator.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ViewAnimator.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewAnimator.class.getName();
     }
 }
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index 587f469..a43a185 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -149,18 +149,9 @@
         updateRunning();
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ViewFlipper.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ViewFlipper.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewFlipper.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/ViewSwitcher.java b/core/java/android/widget/ViewSwitcher.java
index c97770f..2f544cc 100644
--- a/core/java/android/widget/ViewSwitcher.java
+++ b/core/java/android/widget/ViewSwitcher.java
@@ -68,18 +68,9 @@
         super.addView(child, index, params);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ViewSwitcher.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ViewSwitcher.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewSwitcher.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index e0be0ab..6b3faed 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -103,17 +103,8 @@
         return super.dispatchUnhandledMove(focused, direction);
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ZoomButton.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ZoomButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ZoomButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java
index a0aacea..bef1ace 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -109,17 +109,8 @@
         return mZoomIn.hasFocus() || mZoomOut.hasFocus();
     }
 
-    /** @hide */
     @Override
-    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEventInternal(event);
-        event.setClassName(ZoomControls.class.getName());
-    }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        info.setClassName(ZoomControls.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ZoomControls.class.getName();
     }
 }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 144cc33..a410e45 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -505,15 +505,6 @@
             // Header views don't count.
             return;
         }
-        ResolveInfo resolveInfo = mAdapter.resolveInfoForPosition(position, true);
-        if (mResolvingHome && hasManagedProfile()
-                && !supportsManagedProfiles(resolveInfo)) {
-            Toast.makeText(this, String.format(getResources().getString(
-                    com.android.internal.R.string.activity_resolver_work_profiles_support),
-                    resolveInfo.activityInfo.loadLabel(getPackageManager()).toString()),
-                    Toast.LENGTH_LONG).show();
-            return;
-        }
         final int checkedPos = mListView.getCheckedItemPosition();
         final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
         if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
@@ -579,7 +570,6 @@
                 mListView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
                 id == R.id.button_always,
                 mAlwaysUseOption);
-        dismiss();
     }
 
     void startSelected(int which, boolean always, boolean filtered) {
@@ -587,6 +577,14 @@
             return;
         }
         ResolveInfo ri = mAdapter.resolveInfoForPosition(which, filtered);
+        if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) {
+            Toast.makeText(this, String.format(getResources().getString(
+                    com.android.internal.R.string.activity_resolver_work_profiles_support),
+                    ri.activityInfo.loadLabel(getPackageManager()).toString()),
+                    Toast.LENGTH_LONG).show();
+            return;
+        }
+
         Intent intent = mAdapter.intentForPosition(which, filtered);
         onIntentSelected(ri, intent, always);
         finish();
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index aba4bd0..c9b44be 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -800,7 +800,12 @@
             if (args.niceName != null) {
                 String property = "wrap." + args.niceName;
                 if (property.length() > 31) {
-                    property = property.substring(0, 31);
+                    // Properties with a trailing "." are illegal.
+                    if (property.charAt(30) != '.') {
+                        property = property.substring(0, 31);
+                    } else {
+                        property = property.substring(0, 30);
+                    }
                 }
                 args.invokeWith = SystemProperties.get(property);
                 if (args.invokeWith != null && args.invokeWith.length() == 0) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8107985..2477d94 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -355,7 +355,7 @@
                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
             }
             if (id != 0) {
-                if (mResources.getColorStateList(id) == null) {
+                if (mResources.getColorStateList(id, null) == null) {
                     throw new IllegalArgumentException(
                             "Unable to find preloaded color resource #0x"
                             + Integer.toHexString(id)
diff --git a/core/java/com/android/internal/policy/IPolicy.java b/core/java/com/android/internal/policy/IPolicy.java
deleted file mode 100644
index d08b3b4..0000000
--- a/core/java/com/android/internal/policy/IPolicy.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import android.content.Context;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * {@hide}
- */
-
-/* The implementation of this interface must be called Policy and contained
- * within the com.android.internal.policy.impl package */
-public interface IPolicy {
-    public Window makeNewWindow(Context context);
-
-    public LayoutInflater makeNewLayoutInflater(Context context);
-
-    public WindowManagerPolicy makeNewWindowManager();
-
-    public FallbackEventHandler makeNewFallbackEventHandler(Context context);
-}
diff --git a/core/java/com/android/internal/policy/PolicyManager.java b/core/java/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 462b3a9..0000000
--- a/core/java/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import android.content.Context;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * {@hide}
- */
-
-public final class PolicyManager {
-    private static final String POLICY_IMPL_CLASS_NAME =
-        "com.android.internal.policy.impl.Policy";
-
-    private static final IPolicy sPolicy;
-
-    static {
-        // Pull in the actual implementation of the policy at run-time
-        try {
-            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
-            sPolicy = (IPolicy)policyClass.newInstance();
-        } catch (ClassNotFoundException ex) {
-            throw new RuntimeException(
-                    POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
-        } catch (InstantiationException ex) {
-            throw new RuntimeException(
-                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
-        } catch (IllegalAccessException ex) {
-            throw new RuntimeException(
-                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
-        }
-    }
-
-    // Cannot instantiate this class
-    private PolicyManager() {}
-
-    // The static methods to spawn new policy-specific objects
-    public static Window makeNewWindow(Context context) {
-        return sPolicy.makeNewWindow(context);
-    }
-
-    public static LayoutInflater makeNewLayoutInflater(Context context) {
-        return sPolicy.makeNewLayoutInflater(context);
-    }
-
-    public static WindowManagerPolicy makeNewWindowManager() {
-        return sPolicy.makeNewWindowManager();
-    }
-
-    public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
-        return sPolicy.makeNewFallbackEventHandler(context);
-    }
-}
diff --git a/core/java/com/android/internal/transition/EpicenterClipReveal.java b/core/java/com/android/internal/transition/EpicenterClipReveal.java
new file mode 100644
index 0000000..d8a7f16
--- /dev/null
+++ b/core/java/com/android/internal/transition/EpicenterClipReveal.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.transition;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * EpicenterClipReveal captures the {@link View#getClipBounds()} before and
+ * after the scene change and animates between those and the epicenter bounds
+ * during a visibility transition.
+ */
+public class EpicenterClipReveal extends Visibility {
+    private static final String PROPNAME_CLIP = "android:epicenterReveal:clip";
+    private static final String PROPNAME_BOUNDS = "android:epicenterReveal:bounds";
+
+    public EpicenterClipReveal() {}
+
+    public EpicenterClipReveal(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        super.captureStartValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        super.captureEndValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    private void captureValues(TransitionValues values) {
+        final View view = values.view;
+        if (view.getVisibility() == View.GONE) {
+            return;
+        }
+
+        final Rect clip = view.getClipBounds();
+        values.values.put(PROPNAME_CLIP, clip);
+
+        if (clip == null) {
+            final Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
+            values.values.put(PROPNAME_BOUNDS, bounds);
+        }
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, View view,
+            TransitionValues startValues, TransitionValues endValues) {
+        if (endValues == null) {
+            return null;
+        }
+
+        final Rect start = getEpicenter();
+        final Rect end = getBestRect(endValues);
+
+        // Prepare the view.
+        view.setClipBounds(start);
+
+        return createRectAnimator(view, start, end);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, View view,
+            TransitionValues startValues, TransitionValues endValues) {
+        if (startValues == null) {
+            return null;
+        }
+
+        final Rect start = getBestRect(startValues);
+        final Rect end = getEpicenter();
+
+        // Prepare the view.
+        view.setClipBounds(start);
+
+        return createRectAnimator(view, start, end);
+    }
+
+    private Rect getBestRect(TransitionValues values) {
+        final Rect clipRect = (Rect) values.values.get(PROPNAME_CLIP);
+        if (clipRect == null) {
+            return (Rect) values.values.get(PROPNAME_BOUNDS);
+        }
+        return clipRect;
+    }
+
+    private Animator createRectAnimator(View view, Rect start, Rect end) {
+        final RectEvaluator evaluator = new RectEvaluator(new Rect());
+        return ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
+    }
+}
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
new file mode 100644
index 0000000..64e6c69
--- /dev/null
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+    /** Spacer used in horizontal orientation. */
+    private final View mSpacer;
+
+    /** Whether the current configuration allows stacking. */
+    private final boolean mAllowStacked;
+
+    /** Whether the layout is currently stacked. */
+    private boolean mStacked;
+
+    public ButtonBarLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mAllowStacked = context.getResources().getBoolean(R.bool.allow_stacked_button_bar);
+        mSpacer = findViewById(R.id.spacer);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        // Maybe we can fit the content now?
+        if (w > oldw && mStacked) {
+            setStacked(false);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        if (mAllowStacked && getOrientation() == LinearLayout.HORIZONTAL) {
+            final int measuredWidth = getMeasuredWidthAndState();
+            final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+            if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+                setStacked(true);
+
+                // Measure again in the new orientation.
+                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            }
+        }
+    }
+
+    private void setStacked(boolean stacked) {
+        setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+        setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+
+        if (mSpacer != null) {
+            mSpacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+        }
+
+        // Reverse the child order. This is specific to the Material button
+        // bar's layout XML and will probably not generalize.
+        final int childCount = getChildCount();
+        for (int i = childCount - 2; i >= 0; i--) {
+            bringChildToFront(getChildAt(i));
+        }
+
+        mStacked = stacked;
+    }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ec01703..90821dc 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -18,7 +18,6 @@
 
 import android.Manifest;
 import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.ComponentName;
@@ -37,18 +36,12 @@
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
-import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.View;
-import android.widget.Button;
 
-import com.android.internal.R;
 import com.google.android.collect.Lists;
 
 import java.nio.charset.StandardCharsets;
-import libcore.util.HexEncoding;
-
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
@@ -56,6 +49,8 @@
 import java.util.Collection;
 import java.util.List;
 
+import libcore.util.HexEncoding;
+
 /**
  * Utilities for the lock pattern and its settings.
  */
@@ -100,6 +95,11 @@
     public static final int MIN_LOCK_PATTERN_SIZE = 4;
 
     /**
+     * The minimum size of a valid password.
+     */
+    public static final int MIN_LOCK_PASSWORD_SIZE = 4;
+
+    /**
      * The minimum number of dots the user must include in a wrong pattern
      * attempt for it to be counted against the counts that affect
      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
@@ -489,8 +489,9 @@
      */
     public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
         try {
-            if (pattern == null) {
-                throw new IllegalArgumentException("pattern must not be null");
+            if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
+                throw new IllegalArgumentException("pattern must not be null and at least "
+                        + MIN_LOCK_PATTERN_SIZE + " dots long.");
             }
 
             getLockSettings().setLockPattern(patternToString(pattern), userId);
@@ -701,8 +702,9 @@
     public void saveLockPassword(String password, int quality, int userHandle) {
         try {
             DevicePolicyManager dpm = getDevicePolicyManager();
-            if (TextUtils.isEmpty(password)) {
-                throw new IllegalArgumentException("password must not be null nor empty");
+            if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
+                throw new IllegalArgumentException("password must not be null and at least "
+                        + "of length " + MIN_LOCK_PASSWORD_SIZE);
             }
 
             getLockSettings().setLockPassword(password, userHandle);
@@ -1070,21 +1072,6 @@
         return deadline;
     }
 
-    public boolean isEmergencyCallCapable() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
-    }
-
-    public boolean isPukUnlockScreenEnable() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enable_puk_unlock_screen);
-    }
-
-    public boolean isEmergencyCallEnabledWhileSimLocked() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
-    }
-
     private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
         try {
             return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
@@ -1136,58 +1123,6 @@
         }
     }
 
-    /**
-     * Sets the emergency button visibility based on isEmergencyCallCapable().
-     *
-     * If the emergency button is visible, sets the text on the emergency button
-     * to indicate what action will be taken.
-     *
-     * If there's currently a call in progress, the button will take them to the call
-     * @param button The button to update
-     * @param shown Indicates whether the given screen wants the emergency button to show at all
-     * @param showIcon Indicates whether to show a phone icon for the button.
-     */
-    public void updateEmergencyCallButtonState(Button button, boolean shown, boolean showIcon) {
-        if (isEmergencyCallCapable() && shown) {
-            button.setVisibility(View.VISIBLE);
-        } else {
-            button.setVisibility(View.GONE);
-            return;
-        }
-
-        int textId;
-        if (isInCall()) {
-            // show "return to call" text and show phone icon
-            textId = R.string.lockscreen_return_to_call;
-            int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
-            button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
-        } else {
-            textId = R.string.lockscreen_emergency_call;
-            int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
-            button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
-        }
-        button.setText(textId);
-    }
-
-    /**
-     * Resumes a call in progress. Typically launched from the EmergencyCall button
-     * on various lockscreens.
-     */
-    public void resumeCall() {
-        getTelecommManager().showInCallScreen(false);
-    }
-
-    /**
-     * @return {@code true} if there is a call currently in progress, {@code false} otherwise.
-     */
-    public boolean isInCall() {
-        return getTelecommManager().isInCall();
-    }
-
-    private TelecomManager getTelecommManager() {
-        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-    }
-
     public void setPowerButtonInstantlyLocks(boolean enabled) {
         setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, getCurrentOrCallingUserId());
     }
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 4e48454..01e835b 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -593,15 +593,13 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ResolverDrawerLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ResolverDrawerLayout.class.getName();
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ResolverDrawerLayout.class.getName());
         if (isEnabled()) {
             if (mCollapseOffset != 0) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index a306697..825fcad 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -393,17 +393,9 @@
         }
 
         @Override
-        public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
-            super.onInitializeAccessibilityEventInternal(event);
+        public CharSequence getAccessibilityClassName() {
             // This view masquerades as an action bar tab.
-            event.setClassName(ActionBar.Tab.class.getName());
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfoInternal(info);
-            // This view masquerades as an action bar tab.
-            info.setClassName(ActionBar.Tab.class.getName());
+            return ActionBar.Tab.class.getName();
         }
 
         @Override
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 2f987e9..a206e7f 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -148,6 +148,7 @@
         mHasMeasurements = false;
 
         requestLayout();
+        invalidate();
     }
 
     public void setForegroundColor(int color) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index cb9b421..1dd10e1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -87,6 +87,7 @@
     android_graphics_Canvas.cpp \
     android_graphics_Picture.cpp \
     android/graphics/AutoDecodeCancel.cpp \
+    android/graphics/AvoidXfermode.cpp \
     android/graphics/Bitmap.cpp \
     android/graphics/BitmapFactory.cpp \
     android/graphics/Camera.cpp \
diff --git a/core/jni/android/graphics/AvoidXfermode.cpp b/core/jni/android/graphics/AvoidXfermode.cpp
new file mode 100644
index 0000000..9ca1f26
--- /dev/null
+++ b/core/jni/android/graphics/AvoidXfermode.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "AvoidXfermode.h"
+#include "SkColorPriv.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+#include "SkString.h"
+
+AvoidXfermode::AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
+    if (tolerance > 255) {
+        tolerance = 255;
+    }
+    fTolerance = SkToU8(tolerance);
+    fOpColor = opColor;
+    fDistMul = (256 << 14) / (tolerance + 1);
+    fMode = mode;
+}
+
+SkFlattenable* AvoidXfermode::CreateProc(SkReadBuffer& buffer) {
+    const SkColor color = buffer.readColor();
+    const unsigned tolerance = buffer.readUInt();
+    const unsigned mode = buffer.readUInt();
+    return Create(color, tolerance, (Mode)mode);
+}
+
+void AvoidXfermode::flatten(SkWriteBuffer& buffer) const {
+    buffer.writeColor(fOpColor);
+    buffer.writeUInt(fTolerance);
+    buffer.writeUInt(fMode);
+}
+
+// returns 0..31
+static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
+    SkASSERT(r <= SK_R16_MASK);
+    SkASSERT(g <= SK_G16_MASK);
+    SkASSERT(b <= SK_B16_MASK);
+
+    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
+    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
+    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
+
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+// returns 0..255
+static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
+    SkASSERT(r <= 0xFF);
+    SkASSERT(g <= 0xFF);
+    SkASSERT(b <= 0xFF);
+
+    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
+    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
+    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
+
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
+    int tmp = dist * mul - sub;
+    int result = (tmp + (1 << 13)) >> 14;
+
+    return result;
+}
+
+static inline unsigned Accurate255To256(unsigned x) {
+    return x + (x >> 7);
+}
+
+void AvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
+                             const SkAlpha aa[]) const {
+    unsigned    opR = SkColorGetR(fOpColor);
+    unsigned    opG = SkColorGetG(fOpColor);
+    unsigned    opB = SkColorGetB(fOpColor);
+    uint32_t    mul = fDistMul;
+    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
+
+    int MAX, mask;
+
+    if (kTargetColor_Mode == fMode) {
+        mask = -1;
+        MAX = 255;
+    } else {
+        mask = 0;
+        MAX = 0;
+    }
+
+    for (int i = 0; i < count; i++) {
+        int d = color_dist32(dst[i], opR, opG, opB);
+        // now reverse d if we need to
+        d = MAX + (d ^ mask) - mask;
+        SkASSERT((unsigned)d <= 255);
+        d = Accurate255To256(d);
+
+        d = scale_dist_14(d, mul, sub);
+        SkASSERT(d <= 256);
+
+        if (d > 0) {
+            if (aa) {
+                d = SkAlphaMul(d, Accurate255To256(*aa++));
+                if (0 == d) {
+                    continue;
+                }
+            }
+            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
+        }
+    }
+}
+
+static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
+    SkASSERT(scale <= 32);
+    scale <<= 3;
+
+    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
+                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
+                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
+}
+
+void AvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
+                             const SkAlpha aa[]) const {
+    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
+    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
+    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
+    uint32_t    mul = fDistMul;
+    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
+
+    int MAX, mask;
+
+    if (kTargetColor_Mode == fMode) {
+        mask = -1;
+        MAX = 31;
+    } else {
+        mask = 0;
+        MAX = 0;
+    }
+
+    for (int i = 0; i < count; i++) {
+        int d = color_dist16(dst[i], opR, opG, opB);
+        // now reverse d if we need to
+        d = MAX + (d ^ mask) - mask;
+        SkASSERT((unsigned)d <= 31);
+        // convert from 0..31 to 0..32
+        d += d >> 4;
+        d = scale_dist_14(d, mul, sub);
+        SkASSERT(d <= 32);
+
+        if (d > 0) {
+            if (aa) {
+                d = SkAlphaMul(d, Accurate255To256(*aa++));
+                if (0 == d) {
+                    continue;
+                }
+            }
+            dst[i] = SkBlend3216(src[i], dst[i], d);
+        }
+    }
+}
+
+void AvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
+        const SkAlpha aa[]) const {
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void AvoidXfermode::toString(SkString* str) const {
+    str->append("AvoidXfermode: opColor: ");
+    str->appendHex(fOpColor);
+    str->appendf("distMul: %d ", fDistMul);
+
+    static const char* gModeStrings[] = { "Avoid", "Target" };
+
+    str->appendf("mode: %s", gModeStrings[fMode]);
+}
+#endif
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
new file mode 100644
index 0000000..318d7be
--- /dev/null
+++ b/core/jni/android/graphics/AvoidXfermode.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef AvoidXfermode_DEFINED
+#define AvoidXfermode_DEFINED
+
+#include "SkColor.h"
+#include "SkTypes.h"
+#include "SkXfermode.h"
+
+/** \class AvoidXfermode
+
+    This xfermode will draw the src everywhere except on top of the specified
+    color.
+*/
+class AvoidXfermode : public SkXfermode {
+public:
+    enum Mode {
+        kAvoidColor_Mode,   //!< draw everywhere except on the opColor
+        kTargetColor_Mode   //!< draw only on top of the opColor
+    };
+
+    /** This xfermode draws, or doesn't draw, based on the destination's
+        distance from an op-color.
+
+        There are two modes, and each mode interprets a tolerance value.
+
+        Avoid: In this mode, drawing is allowed only on destination pixels that
+               are different from the op-color.
+               Tolerance near 0: avoid any colors even remotely similar to the op-color
+               Tolerance near 255: avoid only colors nearly identical to the op-color
+
+        Target: In this mode, drawing only occurs on destination pixels that
+                are similar to the op-color
+                Tolerance near 0: draw only on colors that are nearly identical to the op-color
+                Tolerance near 255: draw on any colors even remotely similar to the op-color
+     */
+    static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
+        return SkNEW_ARGS(AvoidXfermode, (opColor, tolerance, mode));
+    }
+
+    // overrides from SkXfermode
+    void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
+            const SkAlpha aa[]) const override;
+    void xfer16(uint16_t dst[], const SkPMColor src[], int count,
+            const SkAlpha aa[]) const override;
+    void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
+            const SkAlpha aa[]) const override;
+
+    SK_TO_STRING_OVERRIDE()
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(AvoidXfermode)
+
+protected:
+    AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
+    void flatten(SkWriteBuffer&) const override;
+
+private:
+    SkColor     fOpColor;
+    uint32_t    fDistMul;   // x.14 cached from fTolerance
+    uint8_t     fTolerance;
+    Mode        fMode;
+
+    typedef SkXfermode INHERITED;
+};
+
+#endif
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index b572604..036ece1 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -96,7 +96,7 @@
 }
 
 static void Camera_applyToCanvas(JNIEnv* env, jobject obj, jlong canvasHandle) {
-    SkCanvas* canvas = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas();
+    SkCanvas* canvas = reinterpret_cast<android::Canvas*>(canvasHandle)->asSkCanvas();
     jlong viewHandle = env->GetLongField(obj, gNativeInstanceFieldID);
     Sk3DView* v = reinterpret_cast<Sk3DView*>(viewHandle);
     v->applyToCanvas(canvas);
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 9996ce1..dde1393 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -366,7 +366,7 @@
     if (!canvasHandle) {
         return NULL;
     }
-    SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas();
+    SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->asSkCanvas();
     SkASSERT(c);
     return c;
 }
@@ -511,18 +511,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static bool computeAllocationSize(const SkImageInfo& info, size_t* size, size_t* rowBytes) {
-        int32_t rowBytes32 = SkToS32(info.minRowBytes());
-        int64_t bigSize = (int64_t)info.height() * rowBytes32;
-        if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
-            return false; // allocation will be too large
-        }
+static bool computeAllocationSize(const SkBitmap& bitmap, size_t* size) {
+    int32_t rowBytes32 = SkToS32(bitmap.rowBytes());
+    int64_t bigSize = (int64_t)bitmap.height() * rowBytes32;
+    if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
+        return false; // allocation will be too large
+    }
 
-        *size = sk_64_asS32(bigSize);
-        *rowBytes = rowBytes32;
-
-        SkASSERT(*size >= info.getSafeSize(*rowBytes));
-        return true;
+    *size = sk_64_asS32(bigSize);
+    return true;
 }
 
 jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
@@ -533,11 +530,15 @@
         return NULL;
     }
 
-    size_t size, rowBytes;
-    if (!computeAllocationSize(info, &size, &rowBytes)) {
+    size_t size;
+    if (!computeAllocationSize(*bitmap, &size)) {
         return NULL;
     }
 
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
     jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
                                                              gVMRuntime_newNonMovableArray,
                                                              gByte_class, size);
@@ -580,11 +581,15 @@
         return NULL;
     }
 
-    size_t size, rowBytes;
-    if (!computeAllocationSize(info, &size, &rowBytes)) {
+    size_t size;
+    if (!computeAllocationSize(*bitmap, &size)) {
         return false;
     }
 
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
     void* addr = sk_malloc_flags(size, 0);
     if (NULL == addr) {
         return false;
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 543323c..3f8bfe2 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -120,7 +120,7 @@
     static void drawF(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRectF,
             jlong bitmapHandle, jlong chunkHandle, jlong paintHandle,
             jint destDensity, jint srcDensity) {
-        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->getSkCanvas();
+        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
         const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk  = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         const Paint* paint     = reinterpret_cast<Paint*>(paintHandle);
@@ -139,7 +139,7 @@
     static void drawI(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRect,
             jlong bitmapHandle, jlong chunkHandle, jlong paintHandle,
             jint destDensity, jint srcDensity) {
-        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->getSkCanvas();
+        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
         const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk  = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         const Paint* paint     = reinterpret_cast<Paint*>(paintHandle);
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index c249012..12bfaa2 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -101,7 +101,7 @@
     }
     validate();
     if (NULL != mPicture.get()) {
-        mPicture.get()->playback(canvas->getSkCanvas());
+        mPicture.get()->playback(canvas->asSkCanvas());
     }
 }
 
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 5a3883a..4a424ae 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -18,7 +18,7 @@
 #include "GraphicsJNI.h"
 #include "core_jni_helpers.h"
 
-#include "SkAvoidXfermode.h"
+#include "AvoidXfermode.h"
 #include "SkPixelXorXfermode.h"
 
 namespace android {
@@ -35,8 +35,8 @@
     static jlong avoid_create(JNIEnv* env, jobject, jint opColor,
                                 jint tolerance, jint modeHandle)
     {
-        SkAvoidXfermode::Mode mode = static_cast<SkAvoidXfermode::Mode>(modeHandle);
-        return reinterpret_cast<jlong>(SkAvoidXfermode::Create(opColor, tolerance, mode));
+        AvoidXfermode::Mode mode = static_cast<AvoidXfermode::Mode>(modeHandle);
+        return reinterpret_cast<jlong>(AvoidXfermode::Create(opColor, tolerance, mode));
     }
 
     static jlong pixelxor_create(JNIEnv* env, jobject, jint opColor)
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index d1b1a1a..0b737a7 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "SensorManager"
 
+#include <map>
+
 #include <utils/Log.h>
 #include <utils/Looper.h>
 
@@ -44,7 +46,6 @@
     jfieldID    vendor;
     jfieldID    version;
     jfieldID    handle;
-    jfieldID    type;
     jfieldID    range;
     jfieldID    resolution;
     jfieldID    power;
@@ -55,6 +56,7 @@
     jfieldID    requiredPermission;
     jfieldID    maxDelay;
     jfieldID    flags;
+    jmethodID   setType;
 } gSensorOffsets;
 
 
@@ -71,7 +73,6 @@
     sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
     sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
     sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
-    sensorOffsets.type        = _env->GetFieldID(sensorClass, "mType",      "I");
     sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
     sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
     sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
@@ -84,6 +85,47 @@
                                                         "Ljava/lang/String;");
     sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
     sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
+    sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
+}
+
+/**
+ * A key comparator predicate.
+ * It is used to intern strings associated with Sensor data.
+ * It defines a 'Strict weak ordering' for the interned strings.
+ */
+class InternedStringCompare {
+public:
+    bool operator()(const String8* string1, const String8* string2) const {
+        if (string1 == NULL) {
+            return string2 != NULL;
+        }
+        return string1->compare(*string2) < 0;
+    }
+};
+
+/**
+ * A localized interning mechanism for Sensor strings.
+ * We implement our own interning to avoid the overhead of using java.lang.String#intern().
+ * It is common that Vendor, StringType, and RequirePermission data is common between many of the
+ * Sensors, by interning the memory usage to represent Sensors is optimized.
+ */
+static jstring
+getInternedString(JNIEnv *env, const String8* string) {
+    static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
+
+    jstring internedString;
+    std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
+    if (iterator != internedStrings.end()) {
+        internedString = iterator->second;
+    } else {
+        jstring localString = env->NewStringUTF(string->string());
+        // we are implementing our own interning so expect these strings to be backed by global refs
+        internedString = (jstring) env->NewGlobalRef(localString);
+        internedStrings.insert(std::make_pair(string, internedString));
+        env->DeleteLocalRef(localString);
+    }
+
+    return internedString;
 }
 
 static jint
@@ -93,20 +135,19 @@
 
     Sensor const* const* sensorList;
     size_t count = mgr.getSensorList(&sensorList);
-    if (size_t(next) >= count)
+    if (size_t(next) >= count) {
         return -1;
+    }
 
     Sensor const* const list = sensorList[next];
     const SensorOffsets& sensorOffsets(gSensorOffsets);
-    jstring name = env->NewStringUTF(list->getName().string());
-    jstring vendor = env->NewStringUTF(list->getVendor().string());
-    jstring stringType = env->NewStringUTF(list->getStringType().string());
-    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
+    jstring name = getInternedString(env, &list->getName());
+    jstring vendor = getInternedString(env, &list->getVendor());
+    jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
     env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
     env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
-    env->SetIntField(sensor, sensorOffsets.type,         list->getType());
     env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
     env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
     env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
@@ -115,11 +156,14 @@
                      list->getFifoReservedEventCount());
     env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
                      list->getFifoMaxEventCount());
-    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
     env->SetObjectField(sensor, sensorOffsets.requiredPermission,
                         requiredPermission);
     env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
     env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
+    if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
+        jstring stringType = getInternedString(env, &list->getStringType());
+        env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+    }
     next++;
     return size_t(next) < count ? next : 0;
 }
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index aabf320..7497d8b 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -598,15 +598,10 @@
         ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
         return BAD_VALUE;
     }
-    status_t err = native_window_set_buffers_dimensions(anw.get(), width, height);
-    if (err != NO_ERROR) {
-        ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err);
-        return err;
-    }
 
-    // WAR - Set user dimensions also to avoid incorrect scaling after TextureView orientation
-    // change.
-    err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
+    // Set user dimensions only
+    // The producer dimensions are owned by GL
+    status_t err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
     if (err != NO_ERROR) {
         ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
                 err);
@@ -750,4 +745,3 @@
             gCameraDeviceMethods,
             NELEM(gCameraDeviceMethods));
 }
-
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 0bf269f..ef78fde 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -338,13 +338,15 @@
 }
 
 static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
 {
     const char *c_address = env->GetStringUTFChars(device_address, NULL);
+    const char *c_name = env->GetStringUTFChars(device_name, NULL);
     int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
                                           static_cast <audio_policy_dev_state_t>(state),
-                                          c_address));
+                                          c_address, c_name));
     env->ReleaseStringUTFChars(device_address, c_address);
+    env->ReleaseStringUTFChars(device_name, c_name);
     return (jint) status;
 }
 
@@ -788,10 +790,11 @@
     jintArray jFormats = NULL;
     jobjectArray jGains = NULL;
     jobject jHandle = NULL;
+    jstring jDeviceName = NULL;
     bool useInMask;
 
-    ALOGV("convertAudioPortFromNative id %d role %d type %d",
-                                  nAudioPort->id, nAudioPort->role, nAudioPort->type);
+    ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
+        nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
 
     jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
     if (jSamplingRates == NULL) {
@@ -871,17 +874,21 @@
         goto exit;
     }
 
+    jDeviceName = env->NewStringUTF(nAudioPort->name);
+
     if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
         ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
-                                     jHandle, jSamplingRates, jChannelMasks, jFormats, jGains,
+                                     jHandle, jDeviceName,
+                                     jSamplingRates, jChannelMasks, jFormats, jGains,
                                      nAudioPort->ext.device.type, jAddress);
         env->DeleteLocalRef(jAddress);
     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
         ALOGV("convertAudioPortFromNative is a mix");
         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
-                                     jHandle, nAudioPort->role, jSamplingRates, jChannelMasks,
+                                     jHandle, nAudioPort->role, jDeviceName,
+                                     jSamplingRates, jChannelMasks,
                                      jFormats, jGains);
     } else {
         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
@@ -905,6 +912,9 @@
     env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
 
 exit:
+    if (jDeviceName != NULL) {
+        env->DeleteLocalRef(jDeviceName);
+    }
     if (jSamplingRates != NULL) {
         env->DeleteLocalRef(jSamplingRates);
     }
@@ -1496,7 +1506,7 @@
     {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
-    {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+    {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
@@ -1556,7 +1566,7 @@
     jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
     gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
     gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
-            "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
+            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
     gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
                                                "Landroid/media/AudioHandle;");
     gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
@@ -1594,12 +1604,12 @@
     jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
     gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
     gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
-            "(Landroid/media/AudioHandle;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+            "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
 
     jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
     gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
     gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
-            "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
+            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
 
     jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
     gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
diff --git a/core/res/res/anim/disabled_anim_material.xml b/core/res/res/anim/disabled_anim_material.xml
deleted file mode 100644
index 6a7731e..0000000
--- a/core/res/res/anim/disabled_anim_material.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false">
-        <set>
-            <objectAnimator android:propertyName="alpha"
-                android:duration="@integer/disabled_alpha_animation_duration"
-                android:valueTo="?attr/disabledAlpha"
-                android:valueType="floatType"/>
-        </set>
-    </item>
-    <item>
-        <set>
-            <objectAnimator android:propertyName="alpha"
-                android:duration="@integer/disabled_alpha_animation_duration"
-                android:valueTo="1"
-                android:valueType="floatType"/>
-        </set>
-    </item>
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/color/btn_colored_material.xml
similarity index 93%
rename from core/res/res/color/btn_material_accent.xml
rename to core/res/res/color/btn_colored_material.xml
index 71469b6..b45f824 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/color/btn_colored_material.xml
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
+          android:color="?attr/colorButtonNormal" />
     <item android:color="?attr/colorAccent" />
 </selector>
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/color/btn_colored_text_material.xml
similarity index 82%
copy from core/res/res/color/btn_material_accent.xml
copy to core/res/res/color/btn_colored_text_material.xml
index 71469b6..950d04a 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/color/btn_colored_text_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
+          android:color="?attr/textColorSecondary" />
+    <item android:color="?attr/colorAccent"/>
 </selector>
diff --git a/core/res/res/color/btn_default_material_dark.xml b/core/res/res/color/btn_default_material_dark.xml
index 9be1417..e77af37 100644
--- a/core/res/res/color/btn_default_material_dark.xml
+++ b/core/res/res/color/btn_default_material_dark.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:alpha="@dimen/disabled_alpha_material_dark"
+          android:alpha="?attr/disabledAlpha"
           android:color="@color/button_material_dark"/>
     <item android:color="@color/button_material_dark"/>
 </selector>
diff --git a/core/res/res/color/btn_default_material_light.xml b/core/res/res/color/btn_default_material_light.xml
index af5afe6..9fe5766 100644
--- a/core/res/res/color/btn_default_material_light.xml
+++ b/core/res/res/color/btn_default_material_light.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:alpha="@dimen/disabled_alpha_material_light"
+          android:alpha="?attr/disabledAlpha"
           android:color="@color/button_material_light"/>
     <item android:color="@color/button_material_light"/>
 </selector>
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/color/control_checkable_material.xml
similarity index 74%
copy from core/res/res/color/btn_material_accent.xml
copy to core/res/res/color/control_checkable_material.xml
index 71469b6..c8ef909 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/color/control_checkable_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -17,6 +17,8 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
+          android:color="?attr/colorControlNormal" />
+    <item android:state_checked="true"
+          android:color="?attr/colorControlActivated" />
+    <item android:color="?attr/colorControlNormal" />
 </selector>
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/color/control_default_material.xml
similarity index 87%
copy from core/res/res/color/btn_material_accent.xml
copy to core/res/res/color/control_default_material.xml
index 71469b6..901c680 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/color/control_default_material.xml
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
+          android:color="?attr/colorControlNormal" />
+    <item android:color="?attr/colorControlActivated" />
 </selector>
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/color/switch_track_material.xml
similarity index 76%
copy from core/res/res/color/btn_material_accent.xml
copy to core/res/res/color/switch_track_material.xml
index 71469b6..0c8caa9 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/color/switch_track_material.xml
@@ -16,7 +16,9 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
+          android:color="?attr/colorForeground"
+          android:alpha="?attr/disabledAlpha" />
+    <item android:state_checked="true"
+          android:color="?attr/colorControlActivated" />
+    <item android:color="?attr/colorForeground" />
 </selector>
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/color/tab_indicator_material.xml
similarity index 73%
copy from core/res/res/color/btn_material_accent.xml
copy to core/res/res/color/tab_indicator_material.xml
index 71469b6..9602e92 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/color/tab_indicator_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -15,8 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
+    <item android:state_selected="true"
+          android:color="@color/white" />
+    <item android:color="@color/transparent" />
 </selector>
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index 992a8ff..0000000
--- a/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index 68e17ad..0000000
--- a/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index de7ac29..0000000
--- a/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 9415bc0..0000000
--- a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index 5903856..0000000
--- a/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index e5bface..0000000
--- a/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_clear_mtrl_alpha.png b/core/res/res/drawable-mdpi/ic_clear_mtrl_alpha.png
deleted file mode 100644
index d43e4d1..0000000
--- a/core/res/res/drawable-mdpi/ic_clear_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index bbf5928..0000000
--- a/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 4918d33..0000000
--- a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index d0d0b1e..0000000
--- a/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index dff391f..0000000
--- a/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_clear_mtrl_alpha.png b/core/res/res/drawable-xhdpi/ic_clear_mtrl_alpha.png
deleted file mode 100644
index ddacb59..0000000
--- a/core/res/res/drawable-xhdpi/ic_clear_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index d4bd169..0000000
--- a/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index fd47f15..0000000
--- a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index e1c55ad..0000000
--- a/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index 0d6a39a..0000000
--- a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_clear_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/ic_clear_mtrl_alpha.png
deleted file mode 100644
index 21ed9144..0000000
--- a/core/res/res/drawable-xxhdpi/ic_clear_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 2e7bc12..0000000
--- a/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 3e3174d..0000000
--- a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100755
index c06740b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 1086e9d..0000000
--- a/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 1e4a74c..0000000
--- a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/btn_cab_done_material.xml b/core/res/res/drawable/btn_cab_done_material.xml
deleted file mode 100644
index 36cc196..0000000
--- a/core/res/res/drawable/btn_cab_done_material.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-    <item android:state_pressed="true">
-        <color android:color="?attr/colorControlHighlight" />
-    </item>
-    <item android:state_focused="true" android:state_enabled="true">
-        <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
-            android:tint="?attr/colorControlHighlight" />
-    </item>
-    <item android:state_enabled="true">
-        <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
-            android:tint="?attr/colorButtonNormal" />
-    </item>
-</selector>
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
index 1e05e84..24df879 100644
--- a/core/res/res/drawable/btn_check_material_anim.xml
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -16,118 +16,156 @@
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:state_checked="true">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_checked="true" android:id="@+id/on">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+                android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal" />
     </item>
     <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_001"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_002"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_003"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_004"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_005"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_006"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_007"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_008"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_009"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_010"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_011"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_012"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_013"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_014"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+                        android:tint="?attr/colorControlActivated" />
             </item>
         </animation-list>
     </transition>
     <transition android:fromId="@+id/on" android:toId="@+id/off">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_000"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_001"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_002"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_003"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_004"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_005"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_006"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_007"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_008"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_009"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_010"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_011"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_012"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_013"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_014"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_015"
+                        android:tint="?attr/colorControlNormal" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/btn_radio_material_anim.xml b/core/res/res/drawable/btn_radio_material_anim.xml
index 121e544..bce579e 100644
--- a/core/res/res/drawable/btn_radio_material_anim.xml
+++ b/core/res/res/drawable/btn_radio_material_anim.xml
@@ -16,128 +16,156 @@
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:state_checked="true">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_015"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_000"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_checked="true" android:id="@+id/on">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_015"
-            android:tint="?attr/colorControlActivated" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+                android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_000"
-            android:tint="?attr/colorControlNormal" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal" />
     </item>
     <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+                        android:tint="?attr/colorControlActivated" />
             </item>
         </animation-list>
     </transition>
     <transition android:fromId="@+id/on" android:toId="@+id/off">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_000"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015"
+                        android:tint="?attr/colorControlNormal" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/btn_star_material.xml b/core/res/res/drawable/btn_star_material.xml
index 29862d2..cbea471 100644
--- a/core/res/res/drawable/btn_star_material.xml
+++ b/core/res/res/drawable/btn_star_material.xml
@@ -14,17 +14,6 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true">
-        <bitmap android:src="@drawable/btn_star_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_pressed="true">
-        <bitmap android:src="@drawable/btn_star_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item>
-        <bitmap android:src="@drawable/btn_star_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-</selector>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/btn_star_mtrl_alpha"
+        android:tint="@color/control_checkable_material" />
diff --git a/core/res/res/drawable/btn_toggle_material.xml b/core/res/res/drawable/btn_toggle_material.xml
index f91d4cc..8b19e4a 100644
--- a/core/res/res/drawable/btn_toggle_material.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -23,11 +23,11 @@
         <item>
             <ripple android:color="?attr/colorControlHighlight">
                 <item>
-                    <shape xmlns:android="http://schemas.android.com/apk/res/android"
-                           android:shape="rectangle">
+                    <shape android:shape="rectangle"
+                           android:tint="?attr/colorButtonNormal">
                         <corners android:topLeftRadius="@dimen/control_corner_material"
                                  android:topRightRadius="@dimen/control_corner_material"/>
-                        <solid android:color="?attr/colorButtonNormal" />
+                        <solid android:color="@color/white" />
                         <padding android:left="@dimen/button_padding_horizontal_material"
                                  android:top="@dimen/button_padding_vertical_material"
                                  android:right="@dimen/button_padding_horizontal_material"
@@ -36,17 +36,11 @@
                 </item>
             </ripple>
         </item>
-        <item>
-            <selector xmlns:android="http://schemas.android.com/apk/res/android">
-                <item android:state_checked="false">
-                    <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-                <item android:state_checked="true">
-                    <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </item>
-            </selector>
+        <item android:gravity="bottom|fill_horizontal">
+            <shape android:shape="rectangle">
+                <size android:height="2dp" />
+                <solid android:color="@color/control_checkable_material" />
+            </shape>
         </item>
     </layer-list>
 </inset>
diff --git a/core/res/res/drawable/ic_clear_material.xml b/core/res/res/drawable/ic_clear_material.xml
index 076c0a2..a21f47a 100644
--- a/core/res/res/drawable/ic_clear_material.xml
+++ b/core/res/res/drawable/ic_clear_material.xml
@@ -14,6 +14,13 @@
      limitations under the License.
 -->
 
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_clear_mtrl_alpha"
-    android:tint="?attr/colorControlNormal" />
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?attr/colorControlNormal">
+<path
+    android:pathData="M19,6.41L17.59,5,12,10.59,6.41,5,5,6.41,10.59,12,5,17.59,6.41,19,12,13.41,17.59,19,19,17.59,13.41,12z"
+    android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_material.xml b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
index f2ea30f..89a1787 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_material.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
@@ -14,29 +14,35 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false">
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@id/background">
         <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item>
-        <layer-list>
-            <item android:id="@id/background">
-                <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha"
                     android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:id="@id/secondaryProgress">
-                <scale android:scaleWidth="100%">
-                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </scale>
-            </item>
-            <item android:id="@id/progress">
-                <scale android:scaleWidth="100%">
-                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </scale>
-            </item>
-        </layer-list>
     </item>
-</selector>
+    <item android:id="@id/secondaryProgress">
+        <scale android:scaleWidth="100%">
+            <selector>
+                <item android:state_enabled="false">
+                    <color android:color="@color/transparent" />
+                </item>
+                <item>
+                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
+                                android:tint="?attr/colorControlNormal" />
+                </item>
+            </selector>
+        </scale>
+    </item>
+    <item android:id="@id/progress">
+        <scale android:scaleWidth="100%">
+            <selector>
+                <item android:state_enabled="false">
+                    <color android:color="@color/transparent" />
+                </item>
+                <item>
+                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
+                                android:tint="?attr/colorControlActivated" />
+                </item>
+            </selector>
+        </scale>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml
index d99e367..d5b509f 100644
--- a/core/res/res/drawable/spinner_background_material.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -14,19 +14,22 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-    <item android:state_enabled="false">
-        <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack">
+    <item android:drawable="@drawable/item_background_borderless_material"
+          android:gravity="end|center_vertical"
+          android:width="24dp"
+          android:height="24dp" />
+    <item android:gravity="end|center_vertical">
+        <vector android:width="24dp"
+                android:height="24dp"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0"
+                android:tint="?attr/colorControlNormal">
+            <path android:pathData="M7,10l5,5,5-5z"
+                  android:fillColor="@color/white"/>
+        </vector>
     </item>
-    <item android:state_pressed="false" android:state_focused="false">
-        <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item>
-        <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-</selector>
+    <item android:end="48dp"
+          android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index fab3dc9..69c2f30 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -14,46 +14,8 @@
      limitations under the License.
 -->
 
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:inset="@dimen/control_inset_material">
-    <selector android:autoMirrored="true">
-        <item android:state_enabled="false">
-            <layer-list android:paddingMode="stack">
-                <item>
-                    <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated"
-                        android:alpha="?attr/disabledAlpha" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-                        android:tint="?attr/colorControlActivated"
-                        android:alpha="?attr/disabledAlpha" />
-                </item>
-            </layer-list>
-        </item>
-        <item android:state_pressed="false" android:state_focused="false">
-            <layer-list android:paddingMode="stack">
-                <item>
-                    <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-            </layer-list>
-        </item>
-        <item>
-            <layer-list android:paddingMode="stack">
-                <item>
-                    <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </item>
-            </layer-list>
-        </item>
-    </selector>
-</inset>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack">
+    <item android:drawable="@drawable/edit_text_material" />
+    <item android:drawable="@drawable/spinner_background_material" />
+</layer-list>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index 1ec2f88..a825fe4 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -14,20 +14,15 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false">
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorForeground"
-            android:alpha="0.1" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:gravity="center_vertical|fill_horizontal"
+          android:start="2dp"
+          android:end="2dp">
+        <shape android:shape="rectangle"
+               android:tint="@color/switch_track_material">
+            <corners android:radius="7dp" />
+            <solid android:color="#4dffffff" />
+            <size android:height="14dp" />
+        </shape>
     </item>
-    <item android:state_checked="true">
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="0.3" />
-    </item>
-    <item>
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorForeground"
-            android:alpha="0.3" />
-    </item>
-</selector>
+</layer-list>
diff --git a/core/res/res/drawable/tab_indicator_material.xml b/core/res/res/drawable/tab_indicator_material.xml
index 16362c0..fc52305 100644
--- a/core/res/res/drawable/tab_indicator_material.xml
+++ b/core/res/res/drawable/tab_indicator_material.xml
@@ -14,10 +14,14 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="true">
-        <nine-patch android:src="@drawable/tab_indicator_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:gravity="bottom">
+        <shape android:shape="rectangle"
+               android:tint="?attr/colorControlActivated">
+            <size android:height="2dp" />
+            <solid android:color="@color/tab_indicator_material" />
+        </shape>
     </item>
-    <item android:drawable="@color/transparent" />
-</selector>
+    <item android:bottom="2dp"
+          android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/drawable/textfield_search_material.xml b/core/res/res/drawable/textfield_search_material.xml
index 1c0f5eb..fcd0579 100644
--- a/core/res/res/drawable/textfield_search_material.xml
+++ b/core/res/res/drawable/textfield_search_material.xml
@@ -15,28 +15,20 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true">
-        <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item android:state_window_focused="false" android:state_enabled="false">
-        <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item android:state_enabled="true" android:state_focused="true">
+    <item android:state_window_focused="true"
+          android:state_enabled="true"
+          android:state_focused="true">
         <nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
+                    android:tint="?attr/colorControlActivated" />
     </item>
-    <item android:state_enabled="true" android:state_activated="true">
+    <item android:state_window_focused="true"
+          android:state_enabled="true"
+          android:state_activated="true">
         <nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_enabled="true">
-        <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
+                    android:tint="?attr/colorControlActivated" />
     </item>
     <item>
         <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
+                    android:tint="?attr/colorControlNormal" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/time_picker_header_material.xml b/core/res/res/drawable/time_picker_header_material.xml
index cdb92b6..ef2068a 100644
--- a/core/res/res/drawable/time_picker_header_material.xml
+++ b/core/res/res/drawable/time_picker_header_material.xml
@@ -15,8 +15,6 @@
 -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?attr/colorControlHighlight">
-    <item>
-        <color android:color="?attr/colorAccent" />
-    </item>
+        android:color="?attr/colorControlHighlight">
+    <item android:drawable="?attr/colorAccent" />
 </ripple>
diff --git a/core/res/res/layout/alert_dialog_button_bar_material.xml b/core/res/res/layout/alert_dialog_button_bar_material.xml
new file mode 100644
index 0000000..891bcd5
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_button_bar_material.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<com.android.internal.widget.ButtonBarLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/buttonPanel"
+    style="?attr/buttonBarStyle"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layoutDirection="locale"
+    android:orientation="horizontal"
+    android:paddingStart="12dp"
+    android:paddingEnd="12dp"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="bottom">
+
+    <Button
+        android:id="@+id/button3"
+        style="?attr/buttonBarNeutralButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Space
+        android:id="@+id/spacer"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:visibility="invisible" />
+
+    <Button
+        android:id="@+id/button2"
+        style="?attr/buttonBarNegativeButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@+id/button1"
+        style="?attr/buttonBarPositiveButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</com.android.internal.widget.ButtonBarLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 29bfaa7..c8735b1 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -101,33 +101,5 @@
             android:layout_height="wrap_content" />
     </FrameLayout>
 
-    <LinearLayout android:id="@+id/buttonPanel"
-        style="?attr/buttonBarStyle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layoutDirection="locale"
-        android:orientation="horizontal"
-        android:paddingStart="12dp"
-        android:paddingEnd="12dp"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp"
-        android:gravity="bottom">
-        <Button android:id="@+id/button3"
-            style="?attr/buttonBarNeutralButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:visibility="invisible" />
-        <Button android:id="@+id/button2"
-            style="?attr/buttonBarNegativeButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-        <Button android:id="@+id/button1"
-            style="?attr/buttonBarPositiveButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-    </LinearLayout>
+    <include layout="@layout/alert_dialog_button_bar_material" />
 </LinearLayout>
diff --git a/core/res/res/layout/dialog_custom_title_material.xml b/core/res/res/layout/dialog_custom_title_material.xml
index 248a05e..50ed910 100644
--- a/core/res/res/layout/dialog_custom_title_material.xml
+++ b/core/res/res/layout/dialog_custom_title_material.xml
@@ -27,6 +27,8 @@
         android:layout_weight="0"
         android:gravity="center_vertical|start"
         style="?attr/windowTitleBackgroundStyle" />
+    <View android:layout_width="match_parent"
+        android:layout_height="0dp" />
     <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/core/res/res/layout/dialog_title_icons_material.xml b/core/res/res/layout/dialog_title_icons_material.xml
index 62af096..3866ca7 100644
--- a/core/res/res/layout/dialog_title_icons_material.xml
+++ b/core/res/res/layout/dialog_title_icons_material.xml
@@ -48,6 +48,9 @@
             android:layout_marginStart="8dip" />
     </LinearLayout>
 
+    <View android:layout_width="match_parent"
+        android:layout_height="0dp" />
+
     <FrameLayout
         android:layout_width="match_parent" android:layout_height="wrap_content"
         android:layout_weight="1"
diff --git a/core/res/res/layout/dialog_title_material.xml b/core/res/res/layout/dialog_title_material.xml
index 339d569..1ea7f6e 100644
--- a/core/res/res/layout/dialog_title_material.xml
+++ b/core/res/res/layout/dialog_title_material.xml
@@ -32,6 +32,8 @@
         android:paddingStart="?attr/dialogPreferredPadding"
         android:paddingEnd="?attr/dialogPreferredPadding"
         android:paddingTop="@dimen/dialog_padding_top_material" />
+    <View android:layout_width="match_parent"
+        android:layout_height="0dp" />
     <FrameLayout
         android:layout_width="match_parent" android:layout_height="wrap_content"
         android:layout_weight="1"
diff --git a/core/res/res/layout/preference_dialog_edittext_material.xml b/core/res/res/layout/preference_dialog_edittext_material.xml
new file mode 100644
index 0000000..df76f7f
--- /dev/null
+++ b/core/res/res/layout/preference_dialog_edittext_material.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+<!-- Layout used as the dialog's content View for EditTextPreference. -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginTop="48dp"
+    android:layout_marginBottom="48dp"
+    android:overScrollMode="ifContentScrolls">
+
+    <LinearLayout
+        android:id="@+id/edittext_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="20dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/message"
+            android:layout_marginBottom="48dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="4dp"
+            android:paddingEnd="4dp"
+            android:textColor="?attr/textColorSecondary"
+            style="?attr/textAppearanceSmall" />
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/core/res/res/transition/popup_window_enter.xml b/core/res/res/transition/popup_window_enter.xml
new file mode 100644
index 0000000..92d4c1e
--- /dev/null
+++ b/core/res/res/transition/popup_window_enter.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+               android:transitionOrdering="together">
+     <transition class="com.android.internal.transition.EpicenterClipReveal"
+         android:interpolator="@android:interpolator/accelerate_cubic"
+         android:startDelay="50"
+         android:duration="300" />
+     <fade
+         android:interpolator="@android:interpolator/linear"
+         android:duration="100" />
+</transitionSet>
diff --git a/core/res/res/color/btn_material_accent.xml b/core/res/res/transition/popup_window_exit.xml
similarity index 70%
copy from core/res/res/color/btn_material_accent.xml
copy to core/res/res/transition/popup_window_exit.xml
index 71469b6..5cb9f0b 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/core/res/res/transition/popup_window_exit.xml
@@ -13,10 +13,5 @@
      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="false"
-          android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
-</selector>
+<fade xmlns:android="http://schemas.android.com/apk/res/android"
+      android:interpolator="@android:interpolator/linear" />
diff --git a/core/res/res/values-af/donottranslate-cldr.xml b/core/res/res/values-af/donottranslate-cldr.xml
index 7da5a72..c7f41b4 100755
--- a/core/res/res/values-af/donottranslate-cldr.xml
+++ b/core/res/res/values-af/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 415e6d5..13487d8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is AF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Instellings"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Stembystand"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Sluit nou"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil Verken-met-raak aktiveer. Wanneer Verken-met-raak aangeskakel is, kan jy beskrywings van wat onder jou vinger is hoor of sien, of jy kan gebare uitvoer om interaksie met die foon te hê ."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand gelede"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Voor 1 maand gelede"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 sekonde gelede"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekondes gelede"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuut gelede"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minute gelede"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 uur gelede"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Afgelope <xliff:g id="COUNT">%d</xliff:g> dae"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Verlede maand"</string>
     <string name="older" msgid="5211975022815554840">"Ouer"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"gister"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"oor 1 sekonde"</item>
-    <item quantity="other" msgid="1241926116443974687">"oor <xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"oor 1 minuut"</item>
-    <item quantity="other" msgid="3330713936399448749">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"oor 1 uur"</item>
-    <item quantity="other" msgid="547290677353727389">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"môre"</item>
-    <item quantity="other" msgid="5109449375100953247">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sek. gelede"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek. gelede"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min. gelede"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min. gelede"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 uur gelede"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"gister"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"oor 1 sek."</item>
-    <item quantity="other" msgid="5495880108825805108">"oor <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"oor 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"oor 1 uur"</item>
-    <item quantity="other" msgid="3705373766798013406">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"môre"</item>
-    <item quantity="other" msgid="2973062968038355991">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"by <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android begin tans …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimeer tans berging."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimeer program <xliff:g id="NUMBER_0">%1$d</xliff:g> van <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Berei tans <xliff:g id="APPNAME">%1$s</xliff:g> voor."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Begin programme."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Voltooi herlaai."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> loop"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s wil graag koppel aan %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Program %1$s wil aan Wi-Fi-netwerk %2$s koppel"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"\'n Program"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Begin Wi-Fi Direct. Dit sal die Wi-Fi-kliënt/warmkol afskakel."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-versoek is gewysig tot DIAL-versoek."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-versoek is gewysig tot USSD-versoek."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-versoek is gewysig tot nuwe SS-versoek."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-randpoort"</string>
 </resources>
diff --git a/core/res/res/values-am/donottranslate-cldr.xml b/core/res/res/values-am/donottranslate-cldr.xml
index ea1975c..6afe07f 100755
--- a/core/res/res/values-am/donottranslate-cldr.xml
+++ b/core/res/res/values-am/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %b %-e %Y</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index aafffe8..c7b5b53 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"የአውሮፕላንሁነታ በርቷል"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"የአውሮፕላንሁነታ ጠፍቷል"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ቅንብሮች"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"የድምጽ እርዳታ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"አሁን ቆልፍ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"ከ1 ሴኮንድ በፊት"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ሰኮንዶች በፊት"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"ከ 1 ደቂቃ በፊት"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"ከ1 ሰዓት በፊት"</item>
-    <item quantity="other" msgid="2467273239587587569">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ቀኖች <xliff:g id="COUNT">%d</xliff:g> ያልቃል"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">" ያለፈው ወር"</string>
     <string name="older" msgid="5211975022815554840">"የድሮ"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ትላንትና"</item>
-    <item quantity="other" msgid="2479586466153314633">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"በ1 ሴኮንድ"</item>
-    <item quantity="other" msgid="1241926116443974687">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"በ1 ደቂቃ ውስጥ"</item>
-    <item quantity="other" msgid="3330713936399448749">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"በ  1 ሰዓት"</item>
-    <item quantity="other" msgid="547290677353727389">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ነገ"</item>
-    <item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"ከ 1 ደቂቃ በፊት"</item>
-    <item quantity="other" msgid="851164968597150710">"ከ <xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"ከ1 ሰዓት በፊት"</item>
-    <item quantity="other" msgid="6889970745748538901">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ትላንትና"</item>
-    <item quantity="other" msgid="3453342639616481191">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"በ1 ሴኮንድ"</item>
-    <item quantity="other" msgid="5495880108825805108">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"በ1 ደቂቃ ውስጥ"</item>
-    <item quantity="other" msgid="4216113292706568726">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"በ  1 ሰዓት"</item>
-    <item quantity="other" msgid="3705373766798013406">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ነገ"</item>
-    <item quantity="other" msgid="2973062968038355991">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"በ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"በ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ውስጥ <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android በመጀመር ላይ ነው…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ማከማቻን በማመቻቸት ላይ።"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"መተግበሪያዎች በአግባቡ በመጠቀም ላይ <xliff:g id="NUMBER_0">%1$d</xliff:g> ከ <xliff:g id="NUMBER_1">%2$d</xliff:g> ፡፡"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ን ማዘጋጀት።"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"መተግበሪያዎችን በማስጀመር ላይ፡፡"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"አጨራረስ ማስነሻ፡፡"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ከ%2$s ጋር መገናኘት ይፈልጋል"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"መተግበሪያ %1$s ወደ Wifi Network %2$s መገናኘት ይፈልጋል"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"አንድ መተግበሪያ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"የWi-Fi በቀጥታ  ጀምር።ይህ የWi-Fi ደንበኛ /ድረስ ነጥብ  ያጠፋል።"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ጥያቄ ወደ ደውል ጥያቄ ተሻሽሎዋል።"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ጥያቄ ወደ USSD ጥያቄ ተሻሽሎዋል።"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ጥያቄ ወደ አዲስ SS ጥያቄ ተሻሽሎዋል።"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral ወደብ"</string>
 </resources>
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
index d625752..1be9ed8 100755
--- a/core/res/res/values-ar-rEG/donottranslate-cldr.xml
+++ b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s‏/%s‏/%s"</string>
     <string name="month_day_year">%-e %B، %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d‏/%m‏/%Y</string>
diff --git a/core/res/res/values-ar/donottranslate-cldr.xml b/core/res/res/values-ar/donottranslate-cldr.xml
index d625752..1be9ed8 100755
--- a/core/res/res/values-ar/donottranslate-cldr.xml
+++ b/core/res/res/values-ar/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s‏/%s‏/%s"</string>
     <string name="month_day_year">%-e %B، %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d‏/%m‏/%Y</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 63340fc..2beadc6 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"وضع الطائرة قيد التشغيل"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"وضع الطائرة متوقف"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"الإعدادات"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"المساعد الصوتي"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"قفل الآن"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"‏يريد <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> تمكين ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الهاتف."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"قبل شهر واحد"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل شهر واحد"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"قبل ثانية واحدة"</item>
-    <item quantity="other" msgid="3903706804349556379">"قبل <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"قبل دقيقة واحدة"</item>
-    <item quantity="other" msgid="2176942008915455116">"قبل <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"قبل ساعة واحدة"</item>
-    <item quantity="other" msgid="2467273239587587569">"قبل <xliff:g id="COUNT">%d</xliff:g> ساعات"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"آخر <xliff:g id="COUNT">%d</xliff:g> من الأيام"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"الشهر الماضي"</string>
     <string name="older" msgid="5211975022815554840">"أقدم"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"أمس"</item>
-    <item quantity="other" msgid="2479586466153314633">"قبل <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"في ثانية واحدة"</item>
-    <item quantity="other" msgid="1241926116443974687">"في <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"في دقيقة واحدة"</item>
-    <item quantity="other" msgid="3330713936399448749">"في <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"في ساعة واحدة"</item>
-    <item quantity="other" msgid="547290677353727389">"في <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"غدًا"</item>
-    <item quantity="other" msgid="5109449375100953247">"في <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"قبل ثانية واحدة"</item>
-    <item quantity="other" msgid="3699169366650930415">"قبل <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"قبل دقيقة واحدة"</item>
-    <item quantity="other" msgid="851164968597150710">"قبل <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"قبل ساعة واحدة"</item>
-    <item quantity="other" msgid="6889970745748538901">"قبل <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"أمس"</item>
-    <item quantity="other" msgid="3453342639616481191">"قبل <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"في ثانية واحدة"</item>
-    <item quantity="other" msgid="5495880108825805108">"في <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"في دقيقة واحدة"</item>
-    <item quantity="other" msgid="4216113292706568726">"في <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"في ساعة واحدة"</item>
-    <item quantity="other" msgid="3705373766798013406">"في <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"غدًا"</item>
-    <item quantity="other" msgid="2973062968038355991">"في <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"في <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"في الساعة <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"في <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏جارٍ تشغيل Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"جارٍ تحسين السعة التخزينية."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"جارٍ تحسين التطبيق <xliff:g id="NUMBER_0">%1$d</xliff:g> من <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"جارٍ تحضير <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"بدء التطبيقات."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"جارٍ إعادة التشغيل."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> يعمل"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"‏%1$s يرغب في الاتصال بـ %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏يريد تطبيق %1$s الاتصال بشبكة Wifi ‏%2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"تطبيق"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏اتصال Wi-Fi مباشر"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏يتم تعديل الطلب SS لطلب الاتصال."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏يتم تعديل طلب SS إلى طلب USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏يتم تعديل طلب SS إلى طلب SS الجديد."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏منفذ الأجهزة الطرفية المزودة بكابل USB"</string>
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 479cfcf..b22eb7a 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -967,75 +967,11 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> Toxunaraq Kəşf Et rejimini aktivləşdirmək istəyir. Toxunaraq Kəşf Et açıldığı zaman, barmağınızın altında nə olduğu haqda olan təsvirləri eşidə və ya görə bilərsiniz və ya telefonda insanlarla əlaqəyə keçmək üçün jestlər həyata keçirə bilərsiniz"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay öncə"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay əvvəl"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 saniyə əvvəl"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniyə əvvəl"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 dəqiqə əvvəl"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə əvvəl"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 saat əvvəl"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat əvvəl"</item>
-  </plurals>
   <plurals name="last_num_days">
     <item quantity="other" msgid="3069992808164318268">"Son <xliff:g id="COUNT">%d</xliff:g> gün"</item>
   </plurals>
     <string name="last_month" msgid="3959346739979055432">"Keçən ay"</string>
     <string name="older" msgid="5211975022815554840">"Köhnə"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"dünən"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün əvvəl"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 saniyə ərzində"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniyə içində"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 dəqiqə içində"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə ərzində"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 saata"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saata"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"sabah"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün ərzində"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 saniyə əvvəl"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> san əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 dəqiqə əvvəl"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 saat əvvəl"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"dünən"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 san ərzində"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> san ərzində"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 dəq ərzində"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dəqiqəyə"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 saat ərzində"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saata"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"sabah"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> günə"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> tarixində"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"saat <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> ilində"</string>
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
index 1943517..7c5ba7c 100755
--- a/core/res/res/values-bg/donottranslate-cldr.xml
+++ b/core/res/res/values-bg/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %d.%m.%Y</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2112d8a..1c43360 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Самолетният режим е ВКЛЮЧЕН"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Самолетният режим е ИЗКЛЮЧЕН"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласова помощ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заключване сега"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> иска да активира изследването чрез докосване. Когато услугата е включена, можете да чувате или да виждате описания на това, което е под пръста ви, или да изпълнявате жестове, за да взаимодействате с телефона."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Преди 1 месец"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Преди повече от месец"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Преди 1 секунда"</item>
-    <item quantity="other" msgid="3903706804349556379">"Преди <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Преди 1 минута"</item>
-    <item quantity="other" msgid="2176942008915455116">"Преди <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Преди 1 час"</item>
-    <item quantity="other" msgid="2467273239587587569">"Преди <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Последните <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Последният месец"</string>
     <string name="older" msgid="5211975022815554840">"По-стари"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"вчера"</item>
-    <item quantity="other" msgid="2479586466153314633">"Преди <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"след 1 секунда"</item>
-    <item quantity="other" msgid="1241926116443974687">"след <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"след 1 минута"</item>
-    <item quantity="other" msgid="3330713936399448749">"след <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"след 1 час"</item>
-    <item quantity="other" msgid="547290677353727389">"след <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"утре"</item>
-    <item quantity="other" msgid="5109449375100953247">"след <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Преди 1 сек"</item>
-    <item quantity="other" msgid="3699169366650930415">"Преди <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Преди 1 мин"</item>
-    <item quantity="other" msgid="851164968597150710">"Преди <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Преди 1 час"</item>
-    <item quantity="other" msgid="6889970745748538901">"Преди <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"вчера"</item>
-    <item quantity="other" msgid="3453342639616481191">"Преди <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"след 1 сек"</item>
-    <item quantity="other" msgid="5495880108825805108">"след <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"след 1 мин"</item>
-    <item quantity="other" msgid="4216113292706568726">"след <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"след 1 час"</item>
-    <item quantity="other" msgid="3705373766798013406">"след <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"утре"</item>
-    <item quantity="other" msgid="2973062968038355991">"след <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"на <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"през <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android се стартира…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Хранилището се оптимизира."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимизира се приложение <xliff:g id="NUMBER_0">%1$d</xliff:g> от <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> се подготвя."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Приложенията се стартират."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Зареждането завършва."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> се изпълнява"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s иска да установи връзка с/ъс %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложението %1$s иска да се свърже с Wi-Fi мрежата „%2$s“"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Стартиране на Wi-Fi Direct. Това ще изключи клиентската програма/точката за достъп до Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS заявката е променена на DIAL заявка."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS заявката е променена на USSD заявка."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS заявката е променена на нова SS заявка."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Периферен USB порт"</string>
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index f37b7fb..1d389f3 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"বিমান মোড চালু করা আছে"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"বিমান মোড বন্ধ করা আছে"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"সেটিংস"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ভয়েস সহায়তা"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"এখনই লক করুন"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
     <string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> \'স্পর্শের মাধ্যমে অন্বেষণ করুন\' সক্ষম করতে চাইছে৷ যখন \'স্পর্শের মাধ্যমে অন্বেষণ করুন\' চালু করা হবে তখন আপনার আঙ্গুলের নিয়ন্ত্রণে থাকা জিনিসের বর্ণনাগুলি শুনতে অথবা দেখতে পাবেন অথবা ফোনের সাথে ইন্টারঅ্যাক্ট করার জন্য অঙ্গভঙ্গির সাহায্য নিতে পারবেন৷"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"১ মাস আগে"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"১ মাস আগে"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"১ সেকেন্ড আগে"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড আগে"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"১ মিনিট আগে"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> মিনিট আগে"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"১ ঘন্টা আগে"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা আগে"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"গত <xliff:g id="COUNT">%d</xliff:g> দিনে"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"গত মাস"</string>
     <string name="older" msgid="5211975022815554840">"পুরোনো"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"গতকাল"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> দিন আগে"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"১ সেকেন্ডের মধ্যে"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"১ মিনিটের মধ্যে"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> মিনিটের মধ্যে"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"১ ঘন্টার মধ্যে"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টার মধ্যে"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"আগামীকাল"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> দিনের মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"১ সেকেন্ড আগে"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড আগে"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"১ মিনিট আগে"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> মিনিট আগে"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"১ ঘন্টা আগে"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা আগে"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"গতকাল"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> দিন আগে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"১ সেকেন্ডের মধ্যে"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"১ মিনিটের মধ্যে"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> মিনিটের মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"১ ঘন্টার মধ্যে"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টার মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"আগামীকাল"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> দিনের মধ্যে"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> এ"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> এ"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> এ"</string>
@@ -1259,7 +1194,7 @@
     <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
     <string name="yes" msgid="5362982303337969312">"ঠিক আছে"</string>
     <string name="no" msgid="5141531044935541497">"বাতিল করুন"</string>
-    <string name="dialog_alert_title" msgid="2049658708609043103">"মনোযোগ"</string>
+    <string name="dialog_alert_title" msgid="2049658708609043103">"খেয়াল করুন"</string>
     <string name="loading" msgid="7933681260296021180">"লোড হচ্ছে..."</string>
     <string name="capital_on" msgid="1544682755514494298">"চালু করুন"</string>
     <string name="capital_off" msgid="6815870386972805832">"বন্ধ করুন"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android চালু হচ্ছে…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"সঞ্চয়স্থান অপ্টিমাইজ করা হচ্ছে৷"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>টির মধ্যে <xliff:g id="NUMBER_0">%1$d</xliff:g>টি অ্যাপ্লিকেশান অপ্টিমাইজ করা হচ্ছে৷"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> প্রস্তুত করা হচ্ছে৷"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"অ্যাপ্লিকেশানগুলি শুরু করা হচ্ছে৷"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"চালু করা সম্পূর্ণ হচ্ছে৷"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> চলছে"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi এর সাথে সংযোগ করা যায়নি"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" একটি দুর্বল ইন্টারনেট সংযোগ রয়েছে৷"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের মঞ্জুরি দেবেন?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s %2$s এর সাথে সংযোগ করতে চায়"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"অ্যাপ্লিকেশান %1$s Wifi নেটওয়ার্ক %2$s এর সাথে সংযোগ করতে চায়"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"একটি অ্যাপ্লিকেশান"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ডাইরেক্ট"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ডাইরেক্ট আরম্ভ করুন৷ এটি Wi-Fi client/hotspot কে বন্ধ করবে৷"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS অনুরোধটিকে ডায়াল অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS অনুরোধটিকে নতুন USSD অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS অনুরোধটিকে নতুন SS অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB পেরিফেরাল পোর্ট"</string>
 </resources>
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
index 13f623b..db2d1ec 100755
--- a/core/res/res/values-ca/donottranslate-cldr.xml
+++ b/core/res/res/values-ca/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B de %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %d/%m/%Y</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a2235fd..b60187a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode d\'avió activat"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode d\'avió desactivat"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configuració"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. per veu"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloqueja ara"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració per tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interactuar amb el telèfon."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Fa 1 mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fa més d\'1 mes"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Fa 1 segon"</item>
-    <item quantity="other" msgid="3903706804349556379">"Fa <xliff:g id="COUNT">%d</xliff:g> segons"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Fa 1 minut"</item>
-    <item quantity="other" msgid="2176942008915455116">"Fa <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Fa 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"Fa <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Els darrers <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"El mes passat"</string>
     <string name="older" msgid="5211975022815554840">"Més antigues"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"Ahir"</item>
-    <item quantity="other" msgid="2479586466153314633">"Fa <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"d\'aquí a 1 segon"</item>
-    <item quantity="other" msgid="1241926116443974687">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"d\'aquí a 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"d\'aquí a 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"demà"</item>
-    <item quantity="other" msgid="5109449375100953247">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Fa 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"Fa <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"fa 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Fa <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Fa 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"Fa <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ahir"</item>
-    <item quantity="other" msgid="3453342639616481191">"Fa <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"d\'aquí a 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"d\'aquí a 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"d\'aquí a 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"demà"</item>
-    <item quantity="other" msgid="2973062968038355991">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a les <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"el <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"S\'està iniciant Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"S\'està optimitzant l\'emmagatzematge."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"S\'està optimitzant l\'aplicació <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"S\'està preparant <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"S\'estan iniciant les aplicacions."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"S\'està finalitzant l\'actualització."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s vol connectar amb %2$s."</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'aplicació %1$s vol connectar-se a la xarxa Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicació"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Això desactivarà el client/la zona Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La sol·licitud SS s\'ha transformat en una sol·licitud DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La sol·licitud SS s\'ha transformat en una sol·licitud USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La sol·licitud SS s\'ha transformat en una sol·licitud SS nova."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port perifèric USB"</string>
 </resources>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index 765c51e..51f7e38 100755
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %-e. %-m. %Y</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index dc9eda2..7e02459 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim Letadlo je ZAPNUTÝ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim Letadlo je VYPNUTÝ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Služba <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> požaduje povolení funkce Prozkoumání dotykem. Pokud je funkce Prozkoumání dotykem zapnuta, můžete slyšet nebo vidět popisy objektů pod vaším prstem nebo ovládat telefon gesty."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"před 1 měsícem"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Déle než před 1 měsícem"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"před 1 sekundou"</item>
-    <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"před 1 min"</item>
-    <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"před 1 h"</item>
-    <item quantity="other" msgid="2467273239587587569">"před <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Posledních <xliff:g id="COUNT">%d</xliff:g> dnů"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Poslední měsíc"</string>
     <string name="older" msgid="5211975022815554840">"Starší"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"včera"</item>
-    <item quantity="other" msgid="2479586466153314633">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
-    <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
-    <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"za 1 hodinu"</item>
-    <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"zítra"</item>
-    <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"před 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"před 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"před 1 h"</item>
-    <item quantity="other" msgid="6889970745748538901">"před <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"včera"</item>
-    <item quantity="other" msgid="3453342639616481191">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"za 1 hodinu"</item>
-    <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"zítra"</item>
-    <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dne <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"v <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"roku <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Spouštění systému Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Probíhá optimalizace úložiště."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimalizování aplikace <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Příprava aplikace <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Spouštění aplikací."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončování inicializace."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s se chce připojit k %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikace %1$s se chce připojit k síti Wi-Fi %2$s."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikace"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Přímé připojení sítě Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustit přímé připojení sítě Wi-Fi. Tato možnost vypne provoz sítě Wi-Fi v režimu klient/hotspot."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Požadavek SS byl změněn na požadavek DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Požadavek SS byl změněn na požadavek USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Požadavek SS byl změněn na nový požadavek SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB pro periferní zařízení"</string>
 </resources>
diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml
index 4c7a781..af35257 100755
--- a/core/res/res/values-da/donottranslate-cldr.xml
+++ b/core/res/res/values-da/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %-e. %b %Y</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 1a412c1..1b71828 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er slået FRA"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Indstillinger"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ønsker at aktivere Udforsk ved berøring. Når Udforsk ved berøring er aktiveret, kan du høre eller se beskrivelser af, hvad der er under din finger, eller udføre bevægelser for at interagere med telefonen."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"for 1 måned siden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Før for 1 måned siden"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"for 1 sekund siden"</item>
-    <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"for 1 minut siden"</item>
-    <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"for 1 time siden"</item>
-    <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Seneste <xliff:g id="COUNT">%d</xliff:g> dage"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Seneste måned"</string>
     <string name="older" msgid="5211975022815554840">"Ældre"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"i går"</item>
-    <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
-    <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"om 1 time"</item>
-    <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"for 1 sek. siden"</item>
-    <item quantity="other" msgid="3699169366650930415">"for <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"for 1 min. siden"</item>
-    <item quantity="other" msgid="851164968597150710">"for <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"for 1 time siden"</item>
-    <item quantity="other" msgid="6889970745748538901">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"i går"</item>
-    <item quantity="other" msgid="3453342639616481191">"for <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"om 1 sek."</item>
-    <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"om 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"om 1 time"</item>
-    <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"den <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"i <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android starter..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Lageret optimeres."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimerer app <xliff:g id="NUMBER_0">%1$d</xliff:g> ud af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Forbereder <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Åbner dine apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Gennemfører start."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s vil gerne oprette forbindelse til %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Applikationen %1$s vil gerne have forbindelse til Wi-Fi-netværk %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"En applikation"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette slår Wi-Fi-klient/hotspot fra."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-anmodningen er ændret til en DIAL-anmodning."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-anmodningen er ændret til en USSD-anmodning."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-anmodningen er ændret til en ny SS-anmodning."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Ydre USB-port"</string>
 </resources>
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index 1fa067f..d641e10e 100755
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d.%m.%Y, %H:%M:%S</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 56dd21e..3670b67 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Einstellungen"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Sprachassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\". Wenn \"Tippen &amp; Entdecken\" aktiviert ist, können Sie Beschreibungen dessen hören oder sehen, was sich unter ihren Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"vor 1 Sekunde"</item>
-    <item quantity="other" msgid="3903706804349556379">"vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"vor 1 Minute"</item>
-    <item quantity="other" msgid="2176942008915455116">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"vor 1 Stunde"</item>
-    <item quantity="other" msgid="2467273239587587569">"vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Letzte <xliff:g id="COUNT">%d</xliff:g> Tage"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Letzter Monat"</string>
     <string name="older" msgid="5211975022815554840">"Älter"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"gestern"</item>
-    <item quantity="other" msgid="2479586466153314633">"vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"in 1 Sekunde"</item>
-    <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"in 1 Minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"in 1 Stunde"</item>
-    <item quantity="other" msgid="547290677353727389">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"vor 1 Sekunde"</item>
-    <item quantity="other" msgid="3699169366650930415">"vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"vor 1 Minute"</item>
-    <item quantity="other" msgid="851164968597150710">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"vor 1 Stunde"</item>
-    <item quantity="other" msgid="6889970745748538901">"vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"gestern"</item>
-    <item quantity="other" msgid="3453342639616481191">"vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"in 1 Sekunde"</item>
-    <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"in 1 Minute"</item>
-    <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"in 1 Stunde"</item>
-    <item quantity="other" msgid="3705373766798013406">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"am <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"um <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"im Jahr <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android wird gestartet…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Speicher wird optimiert"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> von <xliff:g id="NUMBER_1">%2$d</xliff:g> wird optimiert..."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> wird vorbereitet"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Apps werden gestartet..."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Start wird abgeschlossen..."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s möchte eine Verbindung mit %2$s herstellen."</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Die App \"%1$s\" möchte eine Verbindung zum WLAN-Netzwerk %2$s herstellen."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Eine App"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-Anfrage wird in DIAL-Anfrage geändert."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-Anfrage wird in USSD-Anfrage geändert."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-Anfrage wird in neue SS-Anfrage geändert."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-Port für Peripheriegeräte"</string>
 </resources>
diff --git a/core/res/res/values-el/donottranslate-cldr.xml b/core/res/res/values-el/donottranslate-cldr.xml
index 7da5a72..c7f41b4 100755
--- a/core/res/res/values-el/donottranslate-cldr.xml
+++ b/core/res/res/values-el/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 737cc1f..da33214 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -42,10 +42,10 @@
     <string name="untitled" msgid="4638956954852782576">"&lt;Χωρίς τίτλο&gt;"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Δεν υπάρχει τηλεφωνικός αριθμός)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Άγνωστο"</string>
-    <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Αυτόματος τηλεφωνητής"</string>
+    <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Αυτ/τος τηλεφωνητής"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
     <string name="mmiError" msgid="5154499457739052907">"Πρόβλημα σύνδεσης ή μη έγκυρος κώδικας MMI."</string>
-    <string name="mmiFdnError" msgid="5224398216385316471">"Η λειτουργία περιορίζεται μόνο σε καθορισμένους αριθμούς κλήσης."</string>
+    <string name="mmiFdnError" msgid="5224398216385316471">"Η λειτουργία περιορίζεται μόνο σε προκαθορισμένους αριθμούς κλήσης."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Η υπηρεσία ενεργοποιήθηκε."</string>
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Η υπηρεσία ενεργοποιήθηκε για:"</string>
     <string name="serviceDisabled" msgid="1937553226592516411">"Η υπηρεσία έχει απενεργοποιηθεί."</string>
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Λειτ. πτήσης είναι ανενεργή"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ρυθμίσεις"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Φων.υποβοηθ."</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Κλείδωμα τώρα"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Η υπηρεσία <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> απαιτεί ενεργοποίηση της Εξερεύνησης μέσω αφής. Όταν είναι ενεργοποιημένη η Εξερεύνηση μέσω αφής, μπορείτε να δείτε ή να ακούσετε περιγραφές για τις επιλογές που βρίσκονται κάτω από το δάχτυλό σας ή να κάνετε κινήσεις αλληλεπίδρασης με το τηλέφωνό σας."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"πριν από 1 μήνα"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Παλαιότερα από 1 μήνα"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"πριν από 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="3903706804349556379">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"πριν από 1 λεπτό"</item>
-    <item quantity="other" msgid="2176942008915455116">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"πριν από 1 ώρα"</item>
-    <item quantity="other" msgid="2467273239587587569">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Τελευταίες <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Τελευταίος μήνας"</string>
     <string name="older" msgid="5211975022815554840">"Παλαιότερα"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"χθες"</item>
-    <item quantity="other" msgid="2479586466153314633">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"σε 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="1241926116443974687">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"σε 1 λεπτό"</item>
-    <item quantity="other" msgid="3330713936399448749">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"σε 1 ώρα"</item>
-    <item quantity="other" msgid="547290677353727389">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"αύριο"</item>
-    <item quantity="other" msgid="5109449375100953247">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"πριν από 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="3699169366650930415">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"πριν από 1 λεπτό"</item>
-    <item quantity="other" msgid="851164968597150710">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"πριν από 1 ώρα"</item>
-    <item quantity="other" msgid="6889970745748538901">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"χθες"</item>
-    <item quantity="other" msgid="3453342639616481191">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"σε 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="5495880108825805108">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"σε 1 λεπτό"</item>
-    <item quantity="other" msgid="4216113292706568726">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"σε 1 ώρα"</item>
-    <item quantity="other" msgid="3705373766798013406">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"αύριο"</item>
-    <item quantity="other" msgid="2973062968038355991">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"στις <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"στις <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"το <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Εκκίνηση Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Βελτιστοποίηση αποθηκευτικού χώρου."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Βελτιστοποίηση της εφαρμογής <xliff:g id="NUMBER_0">%1$d</xliff:g> από <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Προετοιμασία <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Έναρξη εφαρμογών."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Ολοκλήρωση εκκίνησης."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s θα ήθελε να συνδεθεί με %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Η εφαρμογή %1$s θα ήθελε να συνδεθεί με το δίκτυο WiFi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Μια εφαρμογή"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ξεκινήστε τη λειτουργία Wi-Fi Direct. Θα απενεργοποιηθεί η λειτουργία πελάτη/φορητού σημείου πρόσβασης Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Το αίτημα SS τροποποιήθηκε σε αίτημα DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Το αίτημα SS τροποποιήθηκε σε αίτημα USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Το αίτημα SS τροποποιήθηκε σε νέο αίτημα SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Περιφερειακή θύρα USB"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index a7c07d3..69c3aea 100755
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%d/%m/%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index b632f81..57b80df 100755
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%B %-e, %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%Y-%m-%d, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index d099376..db438f2 100755
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y, %H:%M:%S</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index df8b41f..d4d038c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 second ago"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconds ago"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minute ago"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutes ago"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 hour ago"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Last <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Last month"</string>
     <string name="older" msgid="5211975022815554840">"Older"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"yesterday"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"in 1 second"</item>
-    <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"in 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"in 1 hour"</item>
-    <item quantity="other" msgid="547290677353727389">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"tomorrow"</item>
-    <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sec ago"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> secs ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min ago"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> mins ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 hour ago"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"yesterday"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"in 1 sec"</item>
-    <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> secs"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"in 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> mins"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"in 1 hour"</item>
-    <item quantity="other" msgid="3705373766798013406">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"tomorrow"</item>
-    <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"on <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android is starting…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimising storage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimising app <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparing <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s would like to connect to %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS request is modified to DIAL request."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS request is modified to USSD request."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS request is modified to new SS request."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index d099376..db438f2 100755
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y, %H:%M:%S</string>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index 1d9470c..84157fe 100755
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%d-%b-%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index df8b41f..d4d038c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 second ago"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconds ago"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minute ago"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutes ago"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 hour ago"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Last <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Last month"</string>
     <string name="older" msgid="5211975022815554840">"Older"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"yesterday"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"in 1 second"</item>
-    <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"in 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"in 1 hour"</item>
-    <item quantity="other" msgid="547290677353727389">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"tomorrow"</item>
-    <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sec ago"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> secs ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min ago"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> mins ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 hour ago"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"yesterday"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"in 1 sec"</item>
-    <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> secs"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"in 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> mins"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"in 1 hour"</item>
-    <item quantity="other" msgid="3705373766798013406">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"tomorrow"</item>
-    <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"on <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android is starting…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimising storage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimising app <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparing <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s would like to connect to %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS request is modified to DIAL request."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS request is modified to USSD request."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS request is modified to new SS request."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index a4ff357..4e9bec6 100755
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-e/%m/%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rSG/strings.xml b/core/res/res/values-en-rSG/strings.xml
index 09a8490..5ba1082b 100644
--- a/core/res/res/values-en-rSG/strings.xml
+++ b/core/res/res/values-en-rSG/strings.xml
@@ -776,22 +776,6 @@
     <skip />
     <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
     <skip />
-    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
-    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
-    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
-    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
-    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
-    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
-    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
-    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
-    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
-    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
-    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
-    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
-    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
-    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
-    <!-- no translation found for in_num_days:one (5608475533104443893) -->
-    <!-- no translation found for in_num_days:other (3827193006163842267) -->
     <!-- no translation found for preposition_for_date (2689847983632851560) -->
     <skip />
     <!-- no translation found for preposition_for_time (2613388053493148013) -->
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
index 80db6e4..a8e2b2b 100755
--- a/core/res/res/values-en-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rUS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%B %-e, %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rUS/strings.xml b/core/res/res/values-en-rUS/strings.xml
index fdc0d69..adae7f4 100644
--- a/core/res/res/values-en-rUS/strings.xml
+++ b/core/res/res/values-en-rUS/strings.xml
@@ -777,22 +777,6 @@
     <skip />
     <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
     <skip />
-    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
-    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
-    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
-    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
-    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
-    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
-    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
-    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
-    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
-    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
-    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
-    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
-    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
-    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
-    <!-- no translation found for in_num_days:one (5608475533104443893) -->
-    <!-- no translation found for in_num_days:other (3827193006163842267) -->
     <!-- no translation found for preposition_for_date (2689847983632851560) -->
     <skip />
     <!-- no translation found for preposition_for_time (2613388053493148013) -->
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index 7c27604..a4a5308 100755
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%d %b %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 878b48f..8adac31 100755
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %b %-e, %Y</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a9353db..65e50dc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> desea activar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el dispositivo."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace 1 mes."</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"hace 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto."</item>
-    <item quantity="other" msgid="2176942008915455116">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Hace 1 hora."</item>
-    <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas."</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Último mes"</string>
     <string name="older" msgid="5211975022815554840">"Antiguos"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ayer"</item>
-    <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días."</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"en 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"en 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mañana"</item>
-    <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
-    <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"hace 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos."</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Hace 1 hora."</item>
-    <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ayer"</item>
-    <item quantity="other" msgid="3453342639616481191">"Hace <xliff:g id="COUNT">%d</xliff:g> días."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"en 1 segundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"en 1 minuto"</item>
-    <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mañana"</item>
-    <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Iniciando Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizando almacenamiento"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizando la aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicaciones"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando el inicio"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s quiere conectarse a %2$s."</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere conectarse a la red Wi-Fi %2$s."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La solicitud SS cambió por una solicitud DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La solicitud SS cambió por una solicitud USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La solicitud SS cambió por una nueva solicitud SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Puerto USB de periféricos"</string>
 </resources>
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
index d73a715..ca16aa0 100755
--- a/core/res/res/values-es/donottranslate-cldr.xml
+++ b/core/res/res/values-es/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d/%m/%Y, %H:%M:%S</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 96856c0..82cd9c8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión activado. Desactivar"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ajustes"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt; 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Hace 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Hace 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"El mes pasado"</string>
     <string name="older" msgid="5211975022815554840">"Anterior"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"Ayer"</item>
-    <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dentro de 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dentro de 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dentro de 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"dentro de <xliff:g id="COUNT">%d</xliff:g>  horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mañana"</item>
-    <item quantity="other" msgid="5109449375100953247">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
-    <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"hace 1 minuto"</item>
-    <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"Ayer"</item>
-    <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dentro de 1 segundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dentro de 1 minuto"</item>
-    <item quantity="other" msgid="4216113292706568726">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dentro de 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mañana"</item>
-    <item quantity="other" msgid="2973062968038355991">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android se está iniciando…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizando almacenamiento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>..."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicaciones"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando inicio..."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s quiere conectarse a %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere establecer conexión con la red Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La solicitud SS se ha modificado para la solicitud DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La solicitud SS se ha modificado para la solicitud USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La solicitud SS se ha modificado para la nueva solicitud SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Puerto periférico USB"</string>
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index ccb7b9f..bef7626 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Seaded"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Häälabi"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lukusta kohe"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> soovib lubada puudutusega uurimise. Kui puudutusega uurimine on sisse lülitatud, kuulete või näete kirjeldusi asjade kohta, mis on teie sõrme all, või saate suhelda telefoniga liigutuste abil."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 kuu tagasi"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Varem kui 1 kuu tagasi"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 sekund tagasi"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekundit tagasi"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minut tagasi"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutit tagasi"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 tund tagasi"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> tundi tagasi"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Viimased <xliff:g id="COUNT">%d</xliff:g> päeva"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Eelmisel kuul"</string>
     <string name="older" msgid="5211975022815554840">"Vanem"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"eile"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> päeva tagasi"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 sekundi pärast"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 minuti pärast"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minuti pärast"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 tunni pärast"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> tunni pärast"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"homme"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> päeva pärast"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 s tagasi"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sekundit tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minut tagasi"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutit tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 tund tagasi"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> tundi tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"eile"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> päeva tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 sekundi pärast"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 minuti pärast"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> minuti pärast"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 tunni pärast"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> tunni pärast"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"homme"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> päeva pärast"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"kuupäeval <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kell <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"aastal <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android käivitub ..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Salvestusruumi optimeerimine."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g>. rakenduse <xliff:g id="NUMBER_1">%2$d</xliff:g>-st optimeerimine."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> ettevalmistamine."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Rakenduste käivitamine."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Käivitamise lõpuleviimine."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> töötab"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s soovib luua ühenduse võrguga %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Rakendus %1$s soovib luua ühenduse WiFi-võrguga %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Rakendus"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-päring muudeti DIAL-päringuks."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-päring muudeti USSD-päringuks."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-päring muudeti uueks SS-päringuks."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Väline USB-port"</string>
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 51e9fee..a37111b 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hegaldi modua AKTIBATUTA dago"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hegaldi modua DESAKTIBATUTA dago"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ezarpenak"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ahots-laguntza"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blokeatu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
@@ -424,7 +425,7 @@
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Lotu ahots bidezko elkarrekintzako zerbitzuei"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ahots bidezko elkarrekintzako zerbitzu baten goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"kudeatu ahozko gako-esaldiak"</string>
-    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ahoz esandako gako-hitzak hautemateko gako-esaldiak kudeatzea baimentzen die aplikazioei. Aplikazio normalek ez lukete behar."</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ahozko pasahitzak hautemateko gako-esaldiak kudeatzea baimentzen die aplikazioei. Aplikazio normalek ez lukete behar."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Lotu urruneko pantaila batera"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Urruneko pantaila baten goi-mailako interfazera lotzeko aukera ematen dio titularrari. Aplikazio normalek ez dute baimen hau behar."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"lotu widget-zerbitzu batekin"</string>
@@ -559,7 +560,7 @@
     <string name="permdesc_controlVpn" msgid="762852603315861214">"Sare pribatu birtualen behe-mailako eginbideak kontrolatzea baimentzen die aplikazioei."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Grabatu audio-irteera"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Audio-irteera grabatzeko eta birbideratzeko aukera ematen die aplikazioei."</string>
-    <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hauteman Hotword"</string>
+    <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hauteman ahozko pasahitza"</string>
     <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Hotword bidez hauteman daitekeen audioa grabatzeko aukera ematen die aplikazioei. Atzeko planoan grabatzeak ez du bestelako audio-grabazioak (adibidez, bideokamera bidezkoak) egitea eragozten."</string>
     <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audio-bideratzea"</string>
     <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Audio-bideratzea zuzenean kontrolatzea eta audio-gidalerroei gainjartzea baimentzen die aplikazioei."</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> zerbitzuak \"Arakatu ukituta\" eginbidea gaitu nahi du. Eginbide hori aktibatuta dagoenean, hatzaren azpian duzunaren azalpena ikus edo entzun dezakezu, edo telefonoarekin elkarrekintzan aritzeko keinuak egin ditzakezu."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Duela hilabete"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Duela hilabete baino gutxiago"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"duela segundo bat"</item>
-    <item quantity="other" msgid="3903706804349556379">"duela <xliff:g id="COUNT">%d</xliff:g> segundo"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"duela minutu bat"</item>
-    <item quantity="other" msgid="2176942008915455116">"duela <xliff:g id="COUNT">%d</xliff:g> minutu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Duela ordubete"</item>
-    <item quantity="other" msgid="2467273239587587569">"duela <xliff:g id="COUNT">%d</xliff:g> ordu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"azken <xliff:g id="COUNT">%d</xliff:g> egunak"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Azken hilabetea"</string>
     <string name="older" msgid="5211975022815554840">"Zaharragoa"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"atzo"</item>
-    <item quantity="other" msgid="2479586466153314633">"Duela <xliff:g id="COUNT">%d</xliff:g> egun"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"segundo bat barru"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> segundo barru"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"Minutu bat barru"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minutu barru"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"Ordubete barru"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ordu barru"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"bihar"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> egun barru"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"duela segundo bat"</item>
-    <item quantity="other" msgid="3699169366650930415">"duela <xliff:g id="COUNT">%d</xliff:g> segundo"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"duela minutu bat"</item>
-    <item quantity="other" msgid="851164968597150710">"duela <xliff:g id="COUNT">%d</xliff:g> minutu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"duela ordubete"</item>
-    <item quantity="other" msgid="6889970745748538901">"duela <xliff:g id="COUNT">%d</xliff:g> ordu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"atzo"</item>
-    <item quantity="other" msgid="3453342639616481191">"Duela <xliff:g id="COUNT">%d</xliff:g> egun"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"segundo bat barru"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> segundo barru"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"minutu bat barru"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> minutu barru"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ordubete barru"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ordu barru"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"bihar"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> egun barru"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"data: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"urtea: <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android abiarazten ari da…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Memoria optimizatzen."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g> aplikazio optimizatzen."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> prestatzen."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Aplikazioak abiarazten."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Bertsio-berritzea amaitzen."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Interneteko konexio txarra du."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzea baimendu nahi diozu?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s aplikazioak %2$s sarera konektatu nahi du"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s aplikazioak %2$s Wi-Fi sarera konektatu nahi du"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikazio bat"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Hasi Wi-Fi Direct. Wi-Fi bezeroa edo sare publikoa desaktibatuko da."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS eskaera DIAL eskaerara aldatu da."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS eskaera USSD eskaerara aldatu da."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS eskaera SS eskaera berrira aldatu da."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB ataka periferikoa"</string>
 </resources>
diff --git a/core/res/res/values-fa/donottranslate-cldr.xml b/core/res/res/values-fa/donottranslate-cldr.xml
index bb77b31..2821cd5 100755
--- a/core/res/res/values-fa/donottranslate-cldr.xml
+++ b/core/res/res/values-fa/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S،‏ %Y/%-m/%-e</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b04d53c..42ae410 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"حالت هواپیما روشن است"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"حالت هواپیما خاموش است"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"تنظیمات"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"اکنون قفل شود"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> می‌خواهد «کاوش با لمس» را فعال کند. وقتی «کاوش با لمس» فعال است، می‌توانید توضیحاتی را برای آنچه که زیر انگشت شما است مشاهده کرده یا بشنوید یا برای استفاده از تلفن خود از حرکات استفاده کنید."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"۱ ماه قبل"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل از ۱ ماه گذشته"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"۱ ثانیه قبل"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ثانیه قبل"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"۱ دقیقه قبل"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> دقیقه قبل"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"۱ ساعت قبل"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ساعت قبل"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> روز گذشته"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"ماه گذشته"</string>
     <string name="older" msgid="5211975022815554840">"قدیمی تر"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ديروز"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> روز قبل"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"در ۱ ثانیه"</item>
-    <item quantity="other" msgid="1241926116443974687">"در <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"در ۱ دقیقه"</item>
-    <item quantity="other" msgid="3330713936399448749">"در <xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"در ۱ ساعت"</item>
-    <item quantity="other" msgid="547290677353727389">"در <xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"فردا"</item>
-    <item quantity="other" msgid="5109449375100953247">"در <xliff:g id="COUNT">%d</xliff:g> روز"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"۱ ثانیه قبل"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ثانیه قبل"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"۱ دقیقه قبل"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> دقیقه قبل"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"۱ ساعت قبل"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ساعت قبل"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ديروز"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> روز قبل"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"در ۱ ثانیه"</item>
-    <item quantity="other" msgid="5495880108825805108">"در <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"در ۱ دقیقه"</item>
-    <item quantity="other" msgid="4216113292706568726">"در <xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"در ۱ ساعت"</item>
-    <item quantity="other" msgid="3705373766798013406">"در <xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"فردا"</item>
-    <item quantity="other" msgid="2973062968038355991">"در <xliff:g id="COUNT">%d</xliff:g> روز"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"در <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"در <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"در <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏Android در حال راه‌اندازی است..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"بهینه‌سازی فضای ذخیره‌سازی."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"در حال بهینه‌سازی برنامهٔ <xliff:g id="NUMBER_0">%1$d</xliff:g> از <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"آماده‌سازی <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"در حال آغاز برنامه‌ها."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"در حال اتمام راه‌اندازی."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏اتصال به Wi-Fi ممکن نیست"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال اجازه داده شود؟"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"‏%1$s می‌خواهد به %2$s متصل شود"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏برنامه %1$s می‌خواهد به شبکه Wifi ‏%2$s وصل شود"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"برنامه"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏Wi-Fi Direct را شروع کنید. این کار نقطه اتصال/سرویس گیرنده Wi-Fi را غیرفعال خواهد کرد."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏درخواست SS به درخواست DIAL اصلاح می‌شود."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏درخواست SS به درخواست USSD اصلاح می‌شود."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏درخواست SS به درخواست SS جدید اصلاح می‌شود."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏درگاه جانبی USB"</string>
 </resources>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index 8e8c640..eab4957 100755
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k.%M.%S</string>
     <string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-fi/donottranslate-cldr.xml b/core/res/res/values-fi/donottranslate-cldr.xml
index 8e8c640..eab4957 100755
--- a/core/res/res/values-fi/donottranslate-cldr.xml
+++ b/core/res/res/values-fi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k.%M.%S</string>
     <string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 49dd96f..0798424 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Asetukset"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> haluaa ottaa Tutustu koskettamalla -ominaisuuden käyttöön. Kun Tutustu koskettamalla on käytössä, näet tai kuulet kuvauksen sormen alla olevista kohteista ja voit käyttää puhelinta sormieleiden avulla."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"kuukausi sitten"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Yli kuukausi sitten"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 sekunti sitten"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekuntia sitten"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuutti sitten"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuuttia sitten"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 tunti sitten"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> tuntia sitten"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Viimeisen <xliff:g id="COUNT">%d</xliff:g> päivän aikana"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Viime kuussa"</string>
     <string name="older" msgid="5211975022815554840">"Vanhemmat"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"eilen"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> päivää sitten"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 sekunnin kuluttua"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 minuutin kuluttua"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minuutin kuluttua"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 tunnin kuluttua"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> tunnin kuluttua"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"huomenna"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> päivän kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 s sitten"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> s sitten"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min sitten"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min sitten"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 tunti sitten"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> tuntia sitten"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"eilen"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> päivää sitten"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 s kuluttua"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 min kuluttua"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> min kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 tunnin kuluttua"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> tunnin kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"huomenna"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> päivän kuluttua"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"päivä: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"klo <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"vuonna <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android käynnistyy…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimoidaan tallennustilaa."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimoidaan sovellusta <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Valmistellaan: <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Käynnistetään sovelluksia."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Viimeistellään päivitystä."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> käynnissä"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s haluaa yhdistää kohteeseen %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Sovellus %1$s yrittää yhdistää Wi-Fi-verkkoon %2$s."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Sovellus"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora Wi-Fi-yhteys"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora Wi-Fi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-pyyntö muutettiin DIAL-pyynnöksi."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-pyyntö muutettiin USSD-pyynnöksi."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-pyyntö muutettiin uudeksi SS-pyynnöksi."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-oheislaiteportti"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index df8d9c1..52f3e48 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. vocale"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"il y a 1 seconde"</item>
-    <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
-    <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Il y a 1 heure"</item>
-    <item quantity="other" msgid="2467273239587587569">"il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Les <xliff:g id="COUNT">%d</xliff:g> derniers jours"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Le mois dernier"</string>
     <string name="older" msgid="5211975022815554840">"Précédent"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"hier"</item>
-    <item quantity="other" msgid="2479586466153314633">"il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
-    <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
-    <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"demain"</item>
-    <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
-    <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"il y a 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Il y a 1 h"</item>
-    <item quantity="other" msgid="6889970745748538901">"il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"hier"</item>
-    <item quantity="other" msgid="3453342639616481191">"il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
-    <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
-    <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
-    <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"demain"</item>
-    <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"le <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android en cours de démarrage..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimisation du stockage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimisation de l\'application <xliff:g id="NUMBER_0">%1$d</xliff:g> sur <xliff:g id="NUMBER_1">%2$d</xliff:g>…"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Préparation de <xliff:g id="APPNAME">%1$s</xliff:g> en cours…"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Lancement des applications…"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalisation de la mise à jour."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s souhaite se connecter à %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La demande SS a été modifiée et est maintenant une demande DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La demande SS a été modifiée et est maintenant une demande USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La demande SS a été modifiée et est maintenant une nouvelle demande SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB"</string>
 </resources>
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
index 5fc3539..2d6a109 100755
--- a/core/res/res/values-fr/donottranslate-cldr.xml
+++ b/core/res/res/values-fr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y à %H:%M:%S</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 1945e78..667c7cb 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assistance vocale"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Il y a 1 seconde"</item>
-    <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
-    <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"il y a 1 heure"</item>
-    <item quantity="other" msgid="2467273239587587569">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Les <xliff:g id="COUNT">%d</xliff:g> derniers jours"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Le mois dernier"</string>
     <string name="older" msgid="5211975022815554840">"Préc."</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"hier"</item>
-    <item quantity="other" msgid="2479586466153314633">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
-    <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
-    <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"demain"</item>
-    <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
-    <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"il y a 1 minute"</item>
-    <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"il y a 1 heure"</item>
-    <item quantity="other" msgid="6889970745748538901">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"hier"</item>
-    <item quantity="other" msgid="3453342639616481191">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
-    <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
-    <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
-    <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"demain"</item>
-    <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"le <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Démarrage d\'Android en cours"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimisation du stockage en cours…"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimisation de l\'application <xliff:g id="NUMBER_0">%1$d</xliff:g> sur <xliff:g id="NUMBER_1">%2$d</xliff:g>…"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Préparation de <xliff:g id="APPNAME">%1$s</xliff:g> en cours…"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Lancement des applications…"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalisation de la mise à jour."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s souhaite se connecter à %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La requête SS a été remplacée par une requête DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La requête SS a été remplacée par une requête USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La requête SS a été remplacée par une autre requête SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port du périphérique USB"</string>
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 78d223c..220fec7 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo avión está activado"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo avión está desactivado"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quere activar a exploración táctil. Cando a exploración táctil estea activada, poderás escoitar ou ver descricións do contido seleccionado ou realizar xestos para interactuar co teléfono."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hai 1 mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hai máis de 1 mes"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"hai 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"hai <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"hai 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"hai <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Hai 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"hai <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"O mes pasado"</string>
     <string name="older" msgid="5211975022815554840">"Antes"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"onte"</item>
-    <item quantity="other" msgid="2479586466153314633">"Hai <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"En 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"En 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"En <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mañá"</item>
-    <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"hai 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"hai <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"hai 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"hai <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"hai 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"hai <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"onte"</item>
-    <item quantity="other" msgid="3453342639616481191">"Hai <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"en 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"en 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mañá"</item>
-    <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"o <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ás <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"no <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Estase iniciando Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizando almacenamento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicacións."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Está finalizando o arranque"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> está en execución"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar coa rede Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ten unha conexión a Internet deficiente."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s quere conectarse a %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicación %1$s quere conectarse á rede wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Unha aplicación"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Esta acción desactivará o cliente e a zona interactiva da wifi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitude SS transformouse nunha solicitude DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitude SS transformouse nunha solicitude USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitude SS transformouse nunha nova solicitude SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porto periférico USB"</string>
 </resources>
diff --git a/core/res/res/values-h320dp/bools.xml b/core/res/res/values-h320dp/bools.xml
new file mode 100644
index 0000000..8dbc2e1
--- /dev/null
+++ b/core/res/res/values-h320dp/bools.xml
@@ -0,0 +1,21 @@
+<?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.
+*/
+-->
+<resources>
+    <bool name="allow_stacked_button_bar">true</bool>
+</resources>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index 8f30750..b1dc879 100755
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
diff --git a/core/res/res/values-hi/donottranslate-cldr.xml b/core/res/res/values-hi/donottranslate-cldr.xml
index 8f30750..b1dc879 100755
--- a/core/res/res/values-hi/donottranslate-cldr.xml
+++ b/core/res/res/values-hi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d17a5cb..14c1710 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -71,7 +71,7 @@
     <string name="ClirMmi" msgid="7784673673446833091">"आउटगोइंग कॉलर ID"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"कनेक्ट किया गया लाइन आईडी"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"कनेक्ट किया गया लाइन आईडी प्रतिबंध"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"कॉल अग्रेषण"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"कॉल आगे भेजना"</string>
     <string name="CwMmi" msgid="9129678056795016867">"कॉल प्रतीक्षा"</string>
     <string name="BaMmi" msgid="455193067926770581">"कॉल बाधित करना"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"पासवर्ड बदलें"</string>
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाई जहाज मोड चालू है"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाई जहाज मोड बंद है"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"वॉइस सहायक"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्‍पर्श के द्वारा अन्‍वेषण करें सक्षम करना चाहती है. स्‍पर्श के द्वारा अन्‍वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या फ़ोन से डॉयलॉग करने के लिए जेस्‍चर निष्‍पादित कर सकते हैं."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 माह पहले"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 माह से पहले"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 सेकंड पहले"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकंड पहले"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 मिनट पहले"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनट पहले"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 घंटे पहले"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> घंटे पहले"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"अंतिम <xliff:g id="COUNT">%d</xliff:g> दिन"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"पिछला माह"</string>
     <string name="older" msgid="5211975022815554840">"इससे पुराना"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"बीता कल"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिन पहले"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 सेकंड में"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 मिनट में"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> मिनट में"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 घंटे में"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> घंटे में"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"आने वाला कल"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिन में"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 सेकंड पहले"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकंड पहले"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 मिनट पहले"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनट पहले"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 घंटे पहले"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> घंटे पहले"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"बीता कल"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिन पहले"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 सेकंड में"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 मिनट में"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनट में"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 घंटे में"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> घंटे में"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"आने वाला कल"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> दिन में"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> को"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> पर"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> में"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android प्रारंभ हो रहा है…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"मेमोरी ऑप्‍टिमाइज़ हो रही है."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> में से <xliff:g id="NUMBER_0">%1$d</xliff:g> ऐप्स  अनुकूलित हो रहा है."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तैयार हो रहा है."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ऐप्स  प्रारंभ होने वाले हैं"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्‍त हो रहा है."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चल रही है"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s, %2$s से कनेक्ट होना चाहता/चाहती है"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ऐप्‍लिकेशन %2$s वाई-फ़ाई नेटवर्क से कनेक्‍ट करना चाहता है"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ऐप्लिकेशन"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाई-फ़ाई डायरेक्ट"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाई-फ़ाई  डायरेक्ट प्रारंभ करें. इससे वाई-फ़ाई  क्‍लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS अनुरोध को DIAL अनुरोध में बदल दिया गया है."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS अनुरोध को USSD अनुरोध में बदल दिया गया है."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS अनुरोध को नए SS अनुरोध में बदल दिया गया है."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB पेरिफ़ेरल पोर्ट"</string>
 </resources>
diff --git a/core/res/res/values-hr-rHR/donottranslate-cldr.xml b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
index 2eb6d87..ca21a47 100755
--- a/core/res/res/values-hr-rHR/donottranslate-cldr.xml
+++ b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%-e. %B %Y.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
diff --git a/core/res/res/values-hr/donottranslate-cldr.xml b/core/res/res/values-hr/donottranslate-cldr.xml
index 2eb6d87..ca21a47 100755
--- a/core/res/res/values-hr/donottranslate-cldr.xml
+++ b/core/res/res/values-hr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%-e. %B %Y.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 21c9938..919466d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u zrakoplovu"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Isključen je način rada u zrakoplovu"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Postavke"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj sada"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Usluga <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogućiti značajku Istraživanje dodirom. Kad je značajka Istraživanje dodirom uključena, možete čuti ili vidjeti opise onoga što je pod vašim prstom ili izvršiti pokrete za interakciju s telefonom."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prije 1 mjesec"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prije 1 mjesec"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Prije 1 sekundu"</item>
-    <item quantity="other" msgid="3903706804349556379">"prije <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"prije 1 minutu"</item>
-    <item quantity="other" msgid="2176942008915455116">"Prije <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Prije 1 sata"</item>
-    <item quantity="other" msgid="2467273239587587569">"Prije <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Posljednjih ovoliko dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Prošli mjesec"</string>
     <string name="older" msgid="5211975022815554840">"Starije"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"jučer"</item>
-    <item quantity="other" msgid="2479586466153314633">"Prije <xliff:g id="COUNT">%d</xliff:g> dana"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
-    <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
-    <item quantity="other" msgid="3330713936399448749">"za sljedeći broj minuta: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"za 1 sat"</item>
-    <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"sutra"</item>
-    <item quantity="other" msgid="5109449375100953247">"za sljedeći broj dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Prije 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"Prije <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Prije 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Prije <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Prije 1 sat"</item>
-    <item quantity="other" msgid="6889970745748538901">"Prije <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"jučer"</item>
-    <item quantity="other" msgid="3453342639616481191">"Prije <xliff:g id="COUNT">%d</xliff:g> dana"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"za 1 sat"</item>
-    <item quantity="other" msgid="3705373766798013406">"za sljedeći broj sati: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"sutra"</item>
-    <item quantity="other" msgid="2973062968038355991">"za sljedeći broj dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dana <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>."</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Pokretanje Androida..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimiziranje pohrane."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiziranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Pripremanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Završetak inicijalizacije."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Izvodi se <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s traži povezivanje sa sljedećim: %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s traži povezivanje s Wi-Fi mrežom %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Izravni Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni izravan rad s Wi-Fi mrežom. To će isključiti rad s Wi-Fi klijentom/žarišnom točkom."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtjev izmijenjen je u DIAL zahtjev."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtjev izmijenjen je u USSD zahtjev."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtjev izmijenjen je u novi SS zahtjev."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB priključak za periferne uređaje"</string>
 </resources>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index 81e3b12..fd2fe92 100755
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%Y. %B %-e.</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%Y.%m.%d., %-k:%M:%S</string>
diff --git a/core/res/res/values-hu/donottranslate-cldr.xml b/core/res/res/values-hu/donottranslate-cldr.xml
index bafa25e..3f60be7 100755
--- a/core/res/res/values-hu/donottranslate-cldr.xml
+++ b/core/res/res/values-hu/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%Y. %B %-e.</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %Y.%m.%d.</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 978d115..3bcdb52 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -56,7 +56,7 @@
     <string name="badPin" msgid="9015277645546710014">"A megadott régi PIN kód helytelen."</string>
     <string name="badPuk" msgid="5487257647081132201">"A megadott PUK kód helytelen."</string>
     <string name="mismatchPin" msgid="609379054496863419">"A beírt PIN kódok nem egyeznek."</string>
-    <string name="invalidPin" msgid="3850018445187475377">"Írjon be egy 4-8 számjegyű PIN-kódot."</string>
+    <string name="invalidPin" msgid="3850018445187475377">"Írjon be egy 4-8 számjegyű PIN kódot."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"8 számjegyű vagy hosszabb PUK kódot írjon be."</string>
     <string name="needPuk" msgid="919668385956251611">"A SIM kártya le van zárva a PUK kóddal. A feloldáshoz adja meg a PUK kódot."</string>
     <string name="needPuk2" msgid="4526033371987193070">"A SIM kártya feloldásához adja meg a PUK2 kódot."</string>
@@ -75,7 +75,7 @@
     <string name="CwMmi" msgid="9129678056795016867">"Hívásvárakoztatás"</string>
     <string name="BaMmi" msgid="455193067926770581">"Hívásletiltás"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Jelszómódosítás"</string>
-    <string name="PinMmi" msgid="3113117780361190304">"PIN-kód módosítása"</string>
+    <string name="PinMmi" msgid="3113117780361190304">"PIN kód módosítása"</string>
     <string name="CnipMmi" msgid="3110534680557857162">"Szám hívása"</string>
     <string name="CnirMmi" msgid="3062102121430548731">"Hívószám korlátozva"</string>
     <string name="ThreeWCMmi" msgid="9051047170321190368">"Háromutas hívás"</string>
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Repülőgép üzemmód bekapcsolva"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Repülőgép üzemmód kikapcsolva"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Beállítások"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Hangsegéd"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zárolás most"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> aktiválni szeretné a Felfedezés érintéssel funkciót. Amikor be van kapcsolva a Felfedezés érintéssel, akkor hallhatja vagy láthatja annak leírását, ami az ujja alatt van, illetve végrehajthat kézmozdulatokat a telefon kezeléséhez."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 hónapja"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Több mint 1 hónapja"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 másodperce"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> másodperce"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 perce"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> perce"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 órája"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> órája"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Elmúlt <xliff:g id="COUNT">%d</xliff:g> napban"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Múlt hónapban"</string>
     <string name="older" msgid="5211975022815554840">"Régebbi"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"tegnap"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> napja"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 másodperc múlva"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 perc múlva"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> perc múlva"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 óra múlva"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> óra múlva"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"holnap"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 másodperce"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> másodperce"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 perce"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> perce"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 órája"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> órája"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"tegnap"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> napja"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 másodperc múlva"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 perc múlva"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> perc múlva"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 óra múlva"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> óra múlva"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"holnap"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"e napon: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"év: <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Az Android indítása…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Tárhely-optimalizálás."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Alkalmazás optimalizálása: <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> előkészítése."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Kezdő alkalmazások."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Rendszerindítás befejezése."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> fut"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"A(z)%1$s szeretne csatlakozni a következőhöz: %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A(z) %1$s alkalmazás szeretne csatlakozni a következő Wi-Fi hálózathoz: %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Egy alkalmazás"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct elindítása. A Wi-Fi kliens/hotspot ettől leáll."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Az SS-kérés módosítva DIAL-kérésre."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Az SS-kérés módosítva USSD-kérésre."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Az SS-kérés módosítva új SS-kérésre."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-perifériaport"</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 101a726..69621ad 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -22,8 +22,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="byteShort" msgid="8340973892742019101">"Բ"</string>
     <string name="kilobyteShort" msgid="5973789783504771878">"Կբ"</string>
-    <string name="megabyteShort" msgid="6355851576770428922">"Մբ"</string>
-    <string name="gigabyteShort" msgid="3259882455212193214">"Գբ"</string>
+    <string name="megabyteShort" msgid="6355851576770428922">"ՄԲ"</string>
+    <string name="gigabyteShort" msgid="3259882455212193214">"ԳԲ"</string>
     <string name="terabyteShort" msgid="231613018159186962">"Տբ"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"Պբ"</string>
     <string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Կարգավորումներ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Կողպել հիմա"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>-ը ցանկանում է միացնել «Հետազոտում հպման միջոցով» ռեժիմը: Երբ միացված է «Հետազոտում հպման միջոցով» ռեժիմը, դուք կարող եք լսել կամ տեսնել նկարագրությունը, թե ինչ է ձեր մատի տակ, կամ կատարել ժեստեր`  հեռախոսի հետ փոխգործակցելու համար:"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ամիս առաջ"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ավելի շուտ քան 1 ամիս"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 վայրկյան առաջ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> վայրկյան առաջ"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 րոպե առաջ"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> րոպե առաջ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ժամ առաջ"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ժամ առաջ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Վերջին <xliff:g id="COUNT">%d</xliff:g> օրերին"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Անցյալ ամիս"</string>
     <string name="older" msgid="5211975022815554840">"Ավելի հին"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"երեկ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> օր առաջ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 վայրկյանից"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> վայրկյանից"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 րոպեից"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> րոպեից"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 ժամից"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ժամից"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"վաղը"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> օրից"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 վրկ առաջ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> վրկ. առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 րոպե առաջ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> րոպե առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ժամ առաջ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ժամ առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"երեկ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> օր առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 վրկ-ից"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> վրկ-ից"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 րոպեից"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> րոպեից"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 ժամից"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ժամից"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"վաղը"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> օրից"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>-ին"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ժամը <xliff:g id="TIME">%s</xliff:g>-ին"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> թվականին"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android-ը մեկնարկում է…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Պահեստի օպտիմալացում:"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Օպտիմալացվում է հավելված <xliff:g id="NUMBER_0">%1$d</xliff:g>-ը <xliff:g id="NUMBER_1">%2$d</xliff:g>-ից:"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը պատրաստվում է:"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Հավելվածները մեկնարկում են:"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Բեռնումն ավարտվում է:"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>-ն աշխատում է"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ունի թույլ ինտերնետ կապ:"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s օգտվողը ցանկանում է կապվել %2$s-ին"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s հավելվածը ցանկանում է միանալ %2$s Wifi ցանցին"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Հավելված"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ուղիղ"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Մեկնարկել Wi-Fi ուղին: Այն կանջատի Wi-Fi հաճախորդ/թեժ կետ գործողությունը:"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS հարցումը փոխվել է DIAL հարցման:"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS հարցումը փոխվել է USSD հարցման:"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS հարցումը փոխվել է նոր SS հարցման:"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB արտաքին միացք"</string>
 </resources>
diff --git a/core/res/res/values-in-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
index 1f8e542..823b41f 100755
--- a/core/res/res/values-in-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-in-rID/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
     <string name="date_time">%2$s %1$s</string>
diff --git a/core/res/res/values-in/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
index b57823a..35a84eb 100755
--- a/core/res/res/values-in/donottranslate-cldr.xml
+++ b/core/res/res/values-in/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 085939a..c07a78d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat AKTIF"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode pesawat MATI"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Setelan"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Bantuan"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mengaktifkan Menjelajah dengan Sentuhan. Saat Menjelajah dengan Sentuhan diaktifkan, Anda dapat mendengar atau melihat deskripsi dari apa yang ada di bawah jari Anda atau melakukan gerakan untuk berinteraksi dengan ponsel."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 detik lalu"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> detik yang lalu"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 menit yang lalu"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> menit yang lalu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> hari terakhir"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Bulan lalu"</string>
     <string name="older" msgid="5211975022815554840">"Lawas"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"kemarin"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dalam 1 detik"</item>
-    <item quantity="other" msgid="1241926116443974687">"dalam <xliff:g id="COUNT">%d</xliff:g> detik"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dalam 1 menit"</item>
-    <item quantity="other" msgid="3330713936399448749">"dalam <xliff:g id="COUNT">%d</xliff:g> menit"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dalam 1 jam"</item>
-    <item quantity="other" msgid="547290677353727389">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"besok"</item>
-    <item quantity="other" msgid="5109449375100953247">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 detik yang lalu"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> detik yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 menit yang lalu"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> menit yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"kemarin"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dalam 1 detik"</item>
-    <item quantity="other" msgid="5495880108825805108">"dalam <xliff:g id="COUNT">%d</xliff:g> detik"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dalam 1 menit"</item>
-    <item quantity="other" msgid="4216113292706568726">"dalam <xliff:g id="COUNT">%d</xliff:g> menit"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dalam 1 jam"</item>
-    <item quantity="other" msgid="3705373766798013406">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"besok"</item>
-    <item quantity="other" msgid="2973062968038355991">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"pada <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"dalam <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Memulai Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Mengoptimalkan penyimpanan."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Mengoptimalkan aplikasi <xliff:g id="NUMBER_0">%1$d</xliff:g> dari <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Menyiapkan <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulai aplikasi."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Menyelesaikan boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ingin terhubung ke %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin tersambung ke Jaringan Wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikasi"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Memulai Wi-Fi Direct. Opsi ini akan mematikan hotspot/klien Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Permintaan SS diubah menjadi permintaan DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Permintaan SS diubah menjadi permintaan USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Permintaan SS diubah menjadi permintaan SS baru."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port Periferal USB"</string>
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 2839911..c5bf5d2 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"KVEIKT er á flugstillingu"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"SLÖKKT er á flugstillingu"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Stillingar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Raddaðstoð"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Læsa núna"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
@@ -904,7 +905,7 @@
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Brúðkaupsafmæli"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Annað"</string>
     <string name="emailTypeCustom" msgid="8525960257804213846">"Sérsniðið"</string>
-    <string name="emailTypeHome" msgid="449227236140433919">"Heim"</string>
+    <string name="emailTypeHome" msgid="449227236140433919">"Heima"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Vinna"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Annað"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Farsími"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vill kveikja á snertikönnun. Þegar kveikt er á snertikönnun geturðu heyrt eða séð lýsingu á því sem er á skjánum undir fingrinum hverju sinni eða notað bendingar til að stjórna símanum."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Fyrir mánuði"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fyrir meira en mánuði"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"fyrir sekúndu"</item>
-    <item quantity="other" msgid="3903706804349556379">"fyrir <xliff:g id="COUNT">%d</xliff:g> sekúndum"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"fyrir mínútu"</item>
-    <item quantity="other" msgid="2176942008915455116">"fyrir <xliff:g id="COUNT">%d</xliff:g> mínútum"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"fyrir klukkustund"</item>
-    <item quantity="other" msgid="2467273239587587569">"fyrir <xliff:g id="COUNT">%d</xliff:g> klukkustundum"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Síðustu <xliff:g id="COUNT">%d</xliff:g> daga"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Í síðasta mánuði"</string>
     <string name="older" msgid="5211975022815554840">"Eldra"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"í gær"</item>
-    <item quantity="other" msgid="2479586466153314633">"fyrir <xliff:g id="COUNT">%d</xliff:g> dögum"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"eftir sekúndu"</item>
-    <item quantity="other" msgid="1241926116443974687">"eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"eftir mínútu"</item>
-    <item quantity="other" msgid="3330713936399448749">"eftir <xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"eftir klukkustund"</item>
-    <item quantity="other" msgid="547290677353727389">"eftir <xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"á morgun"</item>
-    <item quantity="other" msgid="5109449375100953247">"eftir <xliff:g id="COUNT">%d</xliff:g> daga"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"fyrir sekúndu"</item>
-    <item quantity="other" msgid="3699169366650930415">"fyrir <xliff:g id="COUNT">%d</xliff:g> sekúndum"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"fyrir mínútu"</item>
-    <item quantity="other" msgid="851164968597150710">"fyrir <xliff:g id="COUNT">%d</xliff:g> mínútum"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"fyrir klukkustund"</item>
-    <item quantity="other" msgid="6889970745748538901">"fyrir <xliff:g id="COUNT">%d</xliff:g> klukkustundum"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"í gær"</item>
-    <item quantity="other" msgid="3453342639616481191">"fyrir <xliff:g id="COUNT">%d</xliff:g> dögum"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"eftir sekúndu"</item>
-    <item quantity="other" msgid="5495880108825805108">"eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"eftir mínútu"</item>
-    <item quantity="other" msgid="4216113292706568726">"eftir <xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"eftir klukkustund"</item>
-    <item quantity="other" msgid="3705373766798013406">"eftir <xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"á morgun"</item>
-    <item quantity="other" msgid="2973062968038355991">"eftir <xliff:g id="COUNT">%d</xliff:g> daga"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android er að ræsast…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Fínstillir geymslu."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Fínstillir forrit <xliff:g id="NUMBER_0">%1$d</xliff:g> af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Undirbýr <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Ræsir forrit."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Lýkur ræsingu."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" er með lélegt netsamband."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s vill fá að tengjast %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Forritið %1$s vill tengjast Wi-Fi netinu %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Forrit"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ræsa Wi-Fi Direct. Þetta mun slökkva á Wi-Fi biðlara/aðgangsstað."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-beiðni er breytt í DIAL-beiðni."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-beiðni er breytt í USSD-beiðni."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-beiðni er breytt í nýja SS-beiðni."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-tengi fyrir jaðartæki"</string>
 </resources>
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
index 2aea9510..95ba6dc 100755
--- a/core/res/res/values-it/donottranslate-cldr.xml
+++ b/core/res/res/values-it/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %d/%b/%Y</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index e1f1d7c..1bdc1ff 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Impostazioni"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blocca ora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vuole attivare la funzione Esplora al tocco. Quando la funzione Esplora al tocco è attiva, puoi ascoltare o visualizzare le descrizioni di ciò che stai toccando oppure interagire con il telefono tramite gesti."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mese fa"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Oltre 1 mese fa"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 secondo fa"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuto fa"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ora fa"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Ultimi <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Ultimo mese"</string>
     <string name="older" msgid="5211975022815554840">"Precedente"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ieri"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"tra 1 secondo"</item>
-    <item quantity="other" msgid="1241926116443974687">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"tra 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"tra 1 ora"</item>
-    <item quantity="other" msgid="547290677353727389">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"domani"</item>
-    <item quantity="other" msgid="5109449375100953247">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sec fa"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min fa"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ora fa"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ieri"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"tra 1 sec"</item>
-    <item quantity="other" msgid="5495880108825805108">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"tra 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"tra 1 ora"</item>
-    <item quantity="other" msgid="3705373766798013406">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"domani"</item>
-    <item quantity="other" msgid="2973062968038355991">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"in data <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"alle ore <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"nel <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Avvio di Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Ottimizzazione archiviazione."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ottimizzazione applicazione <xliff:g id="NUMBER_0">%1$d</xliff:g> di <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> in preparazione."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Avvio applicazioni."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Conclusione dell\'avvio."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s vorrebbe connettersi a %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'applicazione %1$s vorrebbe connettersi alla rete Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Un\'applicazione"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Avvia Wi-Fi Direct. Verrà disattivato il client/hotspot Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La richiesta SS è stata modificata in richiesta DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La richiesta SS è stata modificata in richiesta USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La richiesta SS è stata modificata in nuova richiesta SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porta periferica USB"</string>
 </resources>
diff --git a/core/res/res/values-iw/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
index cf05c9d..a9015d0 100755
--- a/core/res/res/values-iw/donottranslate-cldr.xml
+++ b/core/res/res/values-iw/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e ב%B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 196a774..7b6d979 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"מצב טיסה מופעל"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"מצב טיסה כבוי"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"הגדרות"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"נעל עכשיו"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> רוצה להפעיל את התכונה \'חקור על ידי מגע\'. כאשר התכונה \'חקור על ידי מגע\' מופעלת, אתה יכול לשמוע או לראות תיאורים של הפריטים שעליהם אצבעך מונחת או לקיים אינטראקציה עם הטלפון באמצעות תנועות אצבע."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"לפני חודש אחד"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"לפני חודש אחד"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"לפני שנייה אחת"</item>
-    <item quantity="other" msgid="3903706804349556379">"לפני <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"לפני דקה אחת"</item>
-    <item quantity="other" msgid="2176942008915455116">"לפני <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"לפני שעה"</item>
-    <item quantity="other" msgid="2467273239587587569">"לפני <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> הימים האחרונים"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"בחודש שעבר"</string>
     <string name="older" msgid="5211975022815554840">"ישן יותר"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"אתמול"</item>
-    <item quantity="other" msgid="2479586466153314633">"לפני <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"בעוד שנייה אחת"</item>
-    <item quantity="other" msgid="1241926116443974687">"תוך <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"בעוד דקה אחת"</item>
-    <item quantity="other" msgid="3330713936399448749">"תוך <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"תוך שעה אחת"</item>
-    <item quantity="other" msgid="547290677353727389">"תוך <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"מחר"</item>
-    <item quantity="other" msgid="5109449375100953247">"בעוד <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"לפני שנייה אחת"</item>
-    <item quantity="other" msgid="3699169366650930415">"לפני <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"לפני דקה"</item>
-    <item quantity="other" msgid="851164968597150710">"לפני <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"לפני שעה"</item>
-    <item quantity="other" msgid="6889970745748538901">"לפני <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"אתמול"</item>
-    <item quantity="other" msgid="3453342639616481191">"לפני <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"תוך שנייה אחת"</item>
-    <item quantity="other" msgid="5495880108825805108">"תוך <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"תוך דקה אחת"</item>
-    <item quantity="other" msgid="4216113292706568726">"תוך <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"תוך שעה אחת"</item>
-    <item quantity="other" msgid="3705373766798013406">"תוך <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"מחר"</item>
-    <item quantity="other" msgid="2973062968038355991">"בעוד <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"בתאריך <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"בשנת <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏הפעלת Android מתחילה…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"מתבצעת אופטימיזציה של האחסון."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"מבצע אופטימיזציה של אפליקציה <xliff:g id="NUMBER_0">%1$d</xliff:g> מתוך <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"מכין את <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"מפעיל אפליקציות."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"מסיים אתחול."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> פועל"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏אין אפשרות להתחבר ל-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"‏%1$s רוצה להתחבר אל %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏האפליקציה %1$s מנסה להתחבר אל רשת ה-Wi-Fi ‏%2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"אפליקציה"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏Wi-Fi ישיר"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏הפעל Wi-Fi ישיר. פעולה זו תכבה את הנקודה לשיתוף אינטרנט ב-Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏בקשת SS שונתה לבקשת DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏בקשת SS שונתה לבקשת USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏בקשת SS שונתה לבקשת SS חדשה."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏יציאת USB בציוד היקפי"</string>
 </resources>
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
index 21aa0e6..a3c1f64 100755
--- a/core/res/res/values-ja/donottranslate-cldr.xml
+++ b/core/res/res/values-ja/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%Y年%-m月%-e日</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%Y/%m/%d %-k:%M:%S</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 67b72d4..ca4ccda 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>がタッチガイドをONにしようとしています。タッチガイドをONにすると、指の位置にあるアイテムの説明を読み上げたり表示したりできます。また、携帯端末を通常とは違うジェスチャーで操作できます。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1か月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1か月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1分前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1時間前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"過去<xliff:g id="COUNT">%d</xliff:g>日間"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"先月"</string>
     <string name="older" msgid="5211975022815554840">"もっと前"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨日"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1秒後"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1分後"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1時間後"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明日"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1分前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1時間前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨日"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1秒後"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1分後"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1時間後"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明日"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>年"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Androidの起動中…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ストレージを最適化しています。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>個中<xliff:g id="NUMBER_0">%1$d</xliff:g>個のアプリを最適化しています。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>をペア設定しています。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"アプリを起動しています。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ブートを終了しています。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>を実行中"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$sさんが「%2$s」への接続を希望しています"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"アプリ%1$sがWi-Fiネットワーク%2$sへの接続を希望しています"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"アプリ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directを開始します。これによりWi-Fiクライアント/アクセスポイントがOFFになります。"</string>
@@ -1418,7 +1354,7 @@
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"カメラとして接続"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"インストーラとして接続"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USBアクセサリを接続しました"</string>
-    <string name="usb_notification_message" msgid="2290859399983720271">"他のUSBオプションをタップしてください。"</string>
+    <string name="usb_notification_message" msgid="2290859399983720271">"USB接続方法を変更するにはタップしてください。"</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"USBストレージをフォーマットしますか?"</string>
     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"SDカードをフォーマットしますか?"</string>
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"USBストレージに保存されているファイルはすべて消去されます。この操作は元に戻せません。"</string>
@@ -1847,7 +1783,7 @@
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"オフライン再生を解除する前にパスワードの入力を求める"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
-    <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>にダウンロードが終わるまで"</string>
+    <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>にダウンタイムが終わるまで"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ダウンタイム終了まで"</string>
   <plurals name="zen_mode_duration_minutes_summary">
     <item quantity="one" msgid="3177683545388923234">"1分間(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>まで)"</item>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SSリクエストはDIALリクエストに変更されました。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SSリクエストはUSSDリクエストに変更されました。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SSリクエストは新しいSSリクエストに変更されました。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB周辺機器ポート"</string>
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 9ab84bef4..b3ab0e4 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"თვითმფრინავის რეჟიმი ჩართულია."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"თვითმფრინავის რეჟიმი გამორთულია."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"პარამეტრები"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ხმოვანი ასისტ."</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ახლა ჩაკეტვა"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>-ს სურს „შეხებით შესწავლის“ რეჟიმის ჩრთვა. ეს ტელეფონის ჟესტებით მართვისა და იმ ელემენტების აღწერის მოსმენის შესაძლებლობას მოგცემთ, რომელსაც შეეხებით."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"ერთი თვის წინ"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"უფრო ადრე, ვიდრე ერთი თვის წინ"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 წამის წინ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 წუთის უკან"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> წუთის წინ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 საათის წინ"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> საათის წინ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ბოლო <xliff:g id="COUNT">%d</xliff:g> დღე"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"გასული თვე"</string>
     <string name="older" msgid="5211975022815554840">"უფრო ძველი"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"გუშინ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> დღის წინ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 წამში"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> წამში"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 წუთში"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> წუთში"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 საათში"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ხვალ"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> დღეში"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 წმ. წინ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 წუთის წინ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> წუთის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 საათის წინ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> საათის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"გუშინ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> დღის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 წამში"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 წუთში"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> წუთში"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 საათში"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ხვალ"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> დღეში"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"თარიღი: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ზე"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> წელს"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android იწყება…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"მეხსიერების ოპტიმიზირება."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"მიმდინარეობს აპლიკაციების ოპტიმიზაცია. დასრულებულია <xliff:g id="NUMBER_0">%1$d</xliff:g>, სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"ემზადება <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"აპების ჩართვა"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ჩატვირთვის დასასრული."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" აქვს ცუდი ინტერნეტ კავშირი."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s-ს სურს %2$s-თან დაკავშირება"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"განაცხადს %1$s სურს დაუკავშირდეს Wifi ქსელს %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"აპლიკაცია"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ჩართეთ Wi-Fi Direct. ეს გამოიწვევს Wi-Fi კლიენტისა/უსადენო ქსელის გამორთვას."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS მოთხოვნა შეიცვალა DIAL მოთხოვნით."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS მოთხოვნა შეიცვალა USSD მოთხოვნით."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS მოთხოვნა შეიცვალა ახალი SS მოთხოვნით."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"პერიფერიული USB პორტი"</string>
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 255fedc..be1007d 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ұшақ режимі ҚОСУЛЫ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ұшақ режимі ӨШІРУЛІ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Параметрлер"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Дауыс көмекшісі"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Қазір бекіту"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> Сенсор арқылы шолу функциясын іске қосуды қалайды. Сенсор арқылы шолу функциясы қосылғанда саусақ астындағы нысан сипаттарын естуге немесе көруге болады немесе телефонмен қатынасу қимылдарын орындауға болады."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ай бұрын"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Осыған дейін 1 ай бұрын"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 секунд бұрын"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> секунд бұрын"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 минут бұрын"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> минут бұрын"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 сағат бұрын"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> сағат бұрын"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Соңғы <xliff:g id="COUNT">%d</xliff:g> күнде"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Соңғы ай"</string>
     <string name="older" msgid="5211975022815554840">"Ескілеу"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"кеше"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 секундта"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> секундта"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 минутта"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> минутта"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 сағатта"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> сағатта"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ертең"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> күнде"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 секунд бұрын"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> секунд бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 минут бұрын"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> минут бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 сағат бұрын"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> сағат бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"кеше"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 секундта"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> секундта"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 минутта"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> минутта"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 сағатта"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> сағатта"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ертең"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> күнде"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> күні"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> уақытында"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> жылда"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android іске қосылуда…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Қойманы оңтайландыру."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ішінен <xliff:g id="NUMBER_0">%1$d</xliff:g> қолданба оңтайландырылуда."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> дайындалуда."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Қолданбалар іске қосылуда."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Қосуды аяқтауда."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> қосылған"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет байланысы нашар."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s %2$s қосылғысы келеді"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s қолданбасы %2$s Wi-Fi желісіне қосылғысы келеді"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Қолданба"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi тікелей"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Тікелей байланысын бастау. Бұл Wi-Fi клиент/хот-спотты өшіреді."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS сұрауы DIAL сұрауына өзгертілді."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS сұрауы USSD сұрауына өзгертілді."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS сұрауы жаңа SS сұрауына өзгертілді."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB перифериялық порты"</string>
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index f8e88f5..6e06b33 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"បាន​បើក​របៀប​ពេល​ជិះ​យន្ត​ហោះ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បាន​បិទ​របៀបពេលជិះ​យន្តហោះ​"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ការ​កំណត់"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ជំនួយសម្លេង"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ចាក់សោ​ឥឡូវនេះ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ចង់​បើក​ការ​រុករ​ក​ដោយ​ប៉ះ។ ពេល​រុករក​ដោយ​ប៉ះ​ត្រូវ​បាន​បើក​​ អ្នក​អាច​ស្ដាប់​ឮ​ ឬ​ឃើញ​ការ​ពណ៌នា​អ្វី​ដែល​នៅ​ក្រោម​ម្រាមដៃ​របស់​អ្នក​​ ឬ​អនុវត្ត​កាយវិការ​ដើម្បី​មាន​អន្តរកម្ម​ជា​មួយ​ទូរស័ព្ទ។"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ខែ​មុន"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"មុន​ពេល ១ ខែ​មុន"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"១ វិនាទី​មុន"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី​មុន"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"១ នាទី​មុន"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> នាទី​​មុន"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"១ ម៉ោង​មុន"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោង​មុន"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ​ចុងក្រោយ"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"ខែ​មុន"</string>
     <string name="older" msgid="5211975022815554840">"ចាស់​ជាង"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ម្សិលមិញ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ​មុន"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ក្នុង​រយៈ​ពេល ១ វិនាទី"</item>
-    <item quantity="other" msgid="1241926116443974687">"ក្នុង​រយៈ​ពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ក្នុង​រយៈពេល ១ នាទី"</item>
-    <item quantity="other" msgid="3330713936399448749">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"រយៈពេល ១ ម៉ោង"</item>
-    <item quantity="other" msgid="547290677353727389">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ថ្ងៃស្អែក"</item>
-    <item quantity="other" msgid="5109449375100953247">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"១ វិនាទី​មុន"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"១ នាទី​មុន"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> នាទី​​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"១ ម៉ោង​មុន"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោង​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ម្សិលមិញ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ​​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ក្នុង​ពេល​ 1 វិនាទី"</item>
-    <item quantity="other" msgid="5495880108825805108">"ក្នុង​ពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ក្នុង​ពេល 1 នាទី"</item>
-    <item quantity="other" msgid="4216113292706568726">"នៅ​រយៈពេល <xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ក្នុង​រយៈ​ពេល ១ ម៉ោង"</item>
-    <item quantity="other" msgid="3705373766798013406">"ក្នុង​រយៈ​ពេល <xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ថ្ងៃស្អែក"</item>
-    <item quantity="other" msgid="2973062968038355991">"ក្នុង​រយៈ​ពេល <xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"នៅ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"នៅ​ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ក្នុង​ឆ្នាំ <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1305,6 +1240,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android កំពុង​ចាប់ផ្ដើម…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"កំពុងធ្វើឲ្យឧបករណ៍ផ្ទុកមានប្រសិទ្ធភាព។"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"ធ្វើ​ឲ្យ​កម្មវិធី​ប្រសើរ​ឡើង <xliff:g id="NUMBER_0">%1$d</xliff:g> នៃ <xliff:g id="NUMBER_1">%2$d</xliff:g> ។"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"កំពុងរៀបចំ <xliff:g id="APPNAME">%1$s</xliff:g>។"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ចាប់ផ្ដើម​កម្មវិធី។"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"បញ្ចប់​ការ​ចាប់ផ្ដើម។"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
@@ -1350,7 +1286,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មិន​ល្អ។"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាត​ភ្ជាប់?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ចង់​ភ្ជាប់​ %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"កម្មវិធី %1$s ចង់ភ្ជាប់ទៅបណ្តាញ Wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"កម្មវិធី"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"វ៉ាយហ្វាយ​ផ្ទាល់"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើម​វ៉ាយហ្វាយ​ផ្ទាល់។ វា​នឹង​បិទ​វ៉ាយហ្វាយ​ហតស្ពត។"</string>
@@ -1881,4 +1817,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរការហៅទូរស័ព្ទ។"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរ USSD។"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរ SS ថ្មី។"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"ឧបករណ៍រន្ធ USB បន្ថែម"</string>
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 0d18fce..8bb3083 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ಎರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ಎರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ಈಗ ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ಸ್ಪರ್ಶದ ಮೂಲಕ ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಸಕ್ರಿಯಗೊಳಿಸಲು <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ಬಯಸುತ್ತದೆ. ಸ್ಪರ್ಶದ ಮೂಲಕ ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಆನ್ ಮಾಡಿದಾಗ, ಫೋನ್‌ ಜೊತೆ ಸಂವಹನ ನಡೆಸಲು ನಿಮ್ಮ ಬೆರಳಿನ ಅಡಿಯಲ್ಲಿರುವ ವಿವರಣೆಗಳನ್ನು ನೀವು ಆಲಿಸಬಹುದು ಅಥವಾ ವೀಕ್ಷಿಸಬಹುದು ಇಲ್ಲವೇ ಗೆಶ್ಚರ್‌‌ ಮಾಡಬಹುದು."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ತಿಂಗಳ ಹಿಂದೆ"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ತಿಂಗಳ ಹಿಂದಕ್ಕೂ ಮೊದಲು"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 ಸೆಕೆಂಡಿನ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 ನಿಮಿಷದ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ಗಂಟೆ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ಕಳೆದ <xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"ಕಳೆದ ತಿಂಗಳು"</string>
     <string name="older" msgid="5211975022815554840">"ಹಳೆಯದು"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ನಿನ್ನೆ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 ನಿಮಿಷದಲ್ಲಿ"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 ಗಂಟೆಯಲ್ಲಿ"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ನಾಳೆ"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 ಸೆಕೆಂಡಿನ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 ನಿಮಿಷದ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ಗಂಟೆ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ನಿನ್ನೆ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 ನಿಮಿಷದಲ್ಲಿ"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 ಗಂಟೆಯಲ್ಲಿ"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ನಾಳೆ"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> ರಂದು"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> ರಲ್ಲಿ"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> ರಲ್ಲಿ"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ಸಂಗ್ರಹಣೆಯನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="NUMBER_0">%1$d</xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ಬೂಟ್ ಪೂರ್ಣಗೊಳಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ರನ್ ಆಗುತ್ತಿದೆ"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ಕಳಪೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿದೆ."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ಅವರು %2$s ಗೆ ಸಂಪರ್ಕಿಸಲು ಬಯಸುತ್ತಾರೆ"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s ವೈಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು %1$s ಅಪ್ಲಿಕೇಶನ್‌ ಬಯಸುತ್ತದೆ"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ಅಪ್ಲಿಕೇಶನ್"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ಡೈರೆಕ್ಟ್"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ಡೈರೆಕ್ಟ್ ಪ್ರಾರಂಭಿಸಿ. ಇದು Wi-Fi ಕ್ಲೈಂಟ್‌/ಹಾಟ್‌ಸ್ಪಾಟ್ ಅನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ವಿನಂತಿಯನ್ನು DIAL ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ವಿನಂತಿಯನ್ನು USSD ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ವಿನಂತಿಯನ್ನು ಹೊಸ SS ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB ಹೊರಭಾಗದ ಪೋರ್ಟ್"</string>
 </resources>
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
index 083b176..626a480 100755
--- a/core/res/res/values-ko/donottranslate-cldr.xml
+++ b/core/res/res/values-ko/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s. %s. %s."</string>
     <string name="month_day_year">%Y년 %-m월 %-e일</string>
     <string name="time_of_day">%p %-l:%M:%S</string>
     <string name="date_and_time">%Y년 %-m월 %-e일 %p %-l:%M:%S</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c52c351..afa99f3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행기 모드 사용중"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행기 모드 사용중이 아님"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"설정"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"음성 지원"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"지금 잠그기"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>을(를) 사용하려면 \'터치하여 탐색\' 기능을 사용하도록 설정해야 합니다. \'터치하여 탐색\'을 사용하도록 설정하면, 화면을 터치하여 손가락 아래에 표시된 항목에 대한 설명을 듣고 보거나 휴대전화로 상호작용하기 위한 동작을 수행할 수 있습니다."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1초 전"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1분 전"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1시간 전"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"지난 <xliff:g id="COUNT">%d</xliff:g>일"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"지난 달"</string>
     <string name="older" msgid="5211975022815554840">"이전"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"어제"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1초 내"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1분 후"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1시간 후"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"내일"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1초 전"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1분 전"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1시간 전"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"어제"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1초 후"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1분 후"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1시간 후"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"내일"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>년"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android가 시작되는 중…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"저장소 최적화 중"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"앱 <xliff:g id="NUMBER_1">%2$d</xliff:g>개 중 <xliff:g id="NUMBER_0">%1$d</xliff:g>개 최적화 중"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> 준비 중..."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"앱을 시작하는 중입니다."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"부팅 완료"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string>
@@ -1348,9 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for wifi_connect_alert_message (8930084523889618078) -->
-    <skip />
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s 애플리케이션에서 %2$s Wi-Fi 네트워크에 연결하려고 합니다."</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"앱"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct 작업을 시작합니다. 이 작업을 하면 Wi-Fi 클라이언트/핫스팟 작업이 중지됩니다."</string>
@@ -1881,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 요청이 DIAL 요청으로 수정됩니다."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 요청이 USSD 요청으로 수정됩니다."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 요청이 새로운 SS 요청으로 수정됩니다."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 주변기기 포트"</string>
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 2b45690..f4586e1 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -305,6 +305,7 @@
     <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
     <skip />
     <string name="global_action_settings" msgid="1756531602592545966">"Жөндөөлөр"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Үн жардамчысы"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Азыр кулпулоо"</string>
     <!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
     <skip />
@@ -1473,43 +1474,11 @@
     <skip />
     <!-- no translation found for beforeOneMonthDurationPast (909134546836499826) -->
     <skip />
-    <!-- no translation found for num_seconds_ago:one (4869870056547896011) -->
-    <!-- no translation found for num_seconds_ago:other (3903706804349556379) -->
-    <!-- no translation found for num_minutes_ago:one (3306787433088810191) -->
-    <!-- no translation found for num_minutes_ago:other (2176942008915455116) -->
-    <!-- no translation found for num_hours_ago:one (9150797944610821849) -->
-    <!-- no translation found for num_hours_ago:other (2467273239587587569) -->
     <!-- no translation found for last_num_days:other (3069992808164318268) -->
     <!-- no translation found for last_month (3959346739979055432) -->
     <skip />
     <!-- no translation found for older (5211975022815554840) -->
     <skip />
-    <!-- no translation found for num_days_ago:one (861358534398115820) -->
-    <!-- no translation found for num_days_ago:other (2479586466153314633) -->
-    <!-- no translation found for in_num_seconds:one (2729745560954905102) -->
-    <!-- no translation found for in_num_seconds:other (1241926116443974687) -->
-    <!-- no translation found for in_num_minutes:one (8793095251325200395) -->
-    <!-- no translation found for in_num_minutes:other (3330713936399448749) -->
-    <!-- no translation found for in_num_hours:one (7164353342477769999) -->
-    <!-- no translation found for in_num_hours:other (547290677353727389) -->
-    <!-- no translation found for in_num_days:one (5413088743009839518) -->
-    <!-- no translation found for in_num_days:other (5109449375100953247) -->
-    <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
-    <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
-    <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
-    <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
-    <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
-    <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
-    <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
-    <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
-    <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
-    <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
-    <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
-    <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
-    <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
-    <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
-    <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
-    <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
     <!-- no translation found for preposition_for_date (9093949757757445117) -->
     <skip />
     <!-- no translation found for preposition_for_time (5506831244263083793) -->
@@ -1661,6 +1630,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android жүргүзүлүүдө…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Сактагыч ыңгайлаштырылууда."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо ыңгайлаштырылууда."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> даярдалууда."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Колдонмолорду иштетип баштоо"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Жүктөө аякталууда."</string>
     <!-- no translation found for heavy_weight_notification (9087063985776626166) -->
@@ -1717,7 +1687,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" хотспотунун интернет байланышы начар."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s %2$s менен туташкысы келди"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s колдонмосу %2$s Wifi тармагына туташкысы келет"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Колдонмо"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Дайректи иштетүү. Бул Wi-Fi клиентти/хотспотту өчүрөт."</string>
@@ -2357,4 +2327,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS сурамы DIAL сурамына өзгөртүлдү."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS сурамы USSD сурамына өзгөртүлдү."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS сурамы жаңы SS сурамына өзгөртүлдү."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Сырткы оюкча"</string>
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index ed47bbb..ec70266 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ເປີດໂໝດຢູ່ໃນຍົນແລ້ວ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ປິດໂໝດໃນຍົນແລ້ວ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"​ການ​ຕັ້ງ​ຄ່າ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ຊ່ວຍ​ເຫຼືອ​ທາງ​ສຽງ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ລັອກ​ດຽວ​ນີ້"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ຕ້ອງການເປີດນຳໃຊ້ \"ການສຳຫຼວດໂດຍສຳພັດ\". ເມື່ອເປີດ \"ການສຳຫຼວດໂດຍສຳພັດ\" ແລ້ວ ທ່ານຈະສາມາດໄດ້ຍິນ ຫຼືເຫັນຄຳບັນຍາຍວ່າມີຫຍັງຢູ່ກ້ອງນິ້ວມືຂອງທ່ານ ຫຼືໃຊ້ຮູບແບບການເຄື່ອນໄຫວເພື່ອໂຕ້ຕອບກັບໂທລະສັບ."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ເດືອນກ່ອນຫນ້ານີ້"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ຫຼາຍກວ່າ 1 ເດືອນກ່ອນ"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 ວິນາທີກ່ອນ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ວິນາທີກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 ນາທີກ່ອນໜ້ານີ້"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ນາ​ທີ​ທີ່ຜ່ານມາ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ຊົ່ວໂມງກ່ອນໜ້ານີ້"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງທີ່ຜ່ານມາ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> ມື້ທີ່ຜ່ານມາ"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"ເດືອນແລ້ວ"</string>
     <string name="older" msgid="5211975022815554840">"ເກົ່າກວ່າ"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ມື້​ວານ​ນີ້"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ມື້​ກ່ອນ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ໃນອີກ 1 ວິນາທີ"</item>
-    <item quantity="other" msgid="1241926116443974687">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ວິ​ນາ​ທີ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ໃນ 1 ນາທີ"</item>
-    <item quantity="other" msgid="3330713936399448749">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ນາທີ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ໃນ 1 ຊົ່ວໂມງ"</item>
-    <item quantity="other" msgid="547290677353727389">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ມື້ອື່ນ"</item>
-    <item quantity="other" msgid="5109449375100953247">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ມື້"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 ວິນາທີກ່ອນ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ວິ ກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 ນທ ກ່ອນ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> ນທ ກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ຊົ່ວໂມງກ່ອນ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ມື້ວານນີ້"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ມື້ກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ໃນ 1 ວິ"</item>
-    <item quantity="other" msgid="5495880108825805108">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ວິ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ໃນ 1 ນາທີ"</item>
-    <item quantity="other" msgid="4216113292706568726">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ນທ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ໃນ 1 ຊົ່ວໂມງ"</item>
-    <item quantity="other" msgid="3705373766798013406">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ມື້ອື່ນ"</item>
-    <item quantity="other" msgid="2973062968038355991">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ມື້"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"ວັນທີ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ໃນ <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"ກຳ​ລັງ​ເລີ່ມລະ​ບົບ​ Android …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ການ​ປັບ​ບ່ອນ​ເກັບ​ຂໍ້​ມູນ​ໃຫ້​ເໝາະ​ສົມ."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"ກຳລັງ​ປັບປຸງ​ປະສິດທິພາບ​ແອັບຯ​ທີ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຈາກ​ທັງ​ໝົດ <xliff:g id="NUMBER_1">%2$d</xliff:g> ແອັບຯ."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"ກຳ​ລັງ​ກຽມ <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ກຳລັງເປີດແອັບຯ."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ກຳລັງສຳເລັດການເປີດລະບົບ."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກ"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ມີສັນຍານອິນເຕີເນັດທີ່ບໍ່ດີ."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"​ອະ​ນຸ​ຍາດ​ການ​ເຊື່ອມ​ຕໍ່ຫຼື​ບໍ່?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ​ຕ້ອງ​ການ​ທີ່​ຈະ​ເຊື່ອມ​ຕໍ່​ຫາ %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ %1$s ຢາກ​ຈະ​ເຊື່ອມ​ຕໍ່​ກັບ​ເຄືອ​ຂ່າຍ Wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"​ແອັບ​ພລິ​ເຄ​ຊັນ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ເລີ່ມ Wi-Fi Direct. ນີ້ຈະເປັນການປິດ Wi-Fi client/hotspot."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"ການ​ຂໍ SS ຖືກ​ດັດ​ແປງ​ເປັນ​ການ​ຂໍ DIAL ແລ້ວ."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"ການ​ຂໍ SS ຖືກ​ດັດ​ແປງ​ເປັນ​ການ​ຂໍ USSD ແລ້ວ."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"ການ​ຂໍ SS ຖືກ​ດັດ​ແປງ​ເປັນ​ການ​ຂໍ SS ໃໝ່​ແລ້ວ."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"ຊ່ອງ​ຮອບນອກ USB"</string>
 </resources>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index 8a50344..ba4a326 100755
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y m. %B %-e d.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %Y-%m-%d</string>
diff --git a/core/res/res/values-lt/donottranslate-cldr.xml b/core/res/res/values-lt/donottranslate-cldr.xml
index b2368dc..cdca7b6 100755
--- a/core/res/res/values-lt/donottranslate-cldr.xml
+++ b/core/res/res/values-lt/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y m. %B %-e d.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y.%m.%d</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f22ddea..8e8d436 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ĮJUNGTAS lėktuvo režimas"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"lėktuvo režimas IŠJUNGTAS"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nustatymai"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Užrakinti dabar"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"„<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>“ nori įgalinti naršymą liečiant. Kai naršymas liečiant bus įjungtas, galėsite išgirsti ar peržiūrėti pirštu liečiamų elementų aprašus arba atlikdami gestus naudoti telefoną."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prieš 1 mėn."</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prieš maždaug 1 mėnesį"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Prieš 1 sek."</item>
-    <item quantity="other" msgid="3903706804349556379">"Prieš <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Prieš 1 minutę"</item>
-    <item quantity="other" msgid="2176942008915455116">"Prieš <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Prieš 1 valandą"</item>
-    <item quantity="other" msgid="2467273239587587569">"Prieš <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Paskutinės <xliff:g id="COUNT">%d</xliff:g> dienos (-ų)"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Paskutinį mėnesį"</string>
     <string name="older" msgid="5211975022815554840">"Senesni"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"vakar"</item>
-    <item quantity="other" msgid="2479586466153314633">"Prieš <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"po 1 sek."</item>
-    <item quantity="other" msgid="1241926116443974687">"po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"po 1 min."</item>
-    <item quantity="other" msgid="3330713936399448749">"po <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"po 1 val."</item>
-    <item quantity="other" msgid="547290677353727389">"po <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"rytoj"</item>
-    <item quantity="other" msgid="5109449375100953247">"po <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Prieš 1 sek."</item>
-    <item quantity="other" msgid="3699169366650930415">"Prieš <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Prieš 1 min."</item>
-    <item quantity="other" msgid="851164968597150710">"Prieš <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Prieš 1 valandą"</item>
-    <item quantity="other" msgid="6889970745748538901">"Prieš <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"vakar"</item>
-    <item quantity="other" msgid="3453342639616481191">"Prieš <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"po 1 sek."</item>
-    <item quantity="other" msgid="5495880108825805108">"po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"po 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"po <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"po 1 val."</item>
-    <item quantity="other" msgid="3705373766798013406">"po <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"rytoj"</item>
-    <item quantity="other" msgid="2973062968038355991">"po <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> m."</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Paleidžiama „Android“…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizuojama saugykla."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizuojama <xliff:g id="NUMBER_0">%1$d</xliff:g> progr. iš <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Ruošiama „<xliff:g id="APPNAME">%1$s</xliff:g>“."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Paleidžiamos programos."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Užbaigiamas paleidimas."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Vykdoma „<xliff:g id="APP">%1$s</xliff:g>“"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"„%1$s“ nori prisijungti prie „%2$s“"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programa „%1$s“ nori prisijungti prie „Wi-Fi“ tinklo „%2$s“"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Programa"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Paleiskite „Wi-Fi Direct“. Bus išjungta „Wi-Fi“ programa / viešosios interneto prieigos taškas."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS užklausa pakeista į DIAL užklausą."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS užklausa pakeista į USSD užklausą."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS užklausa pakeista į naują SS užklausą."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB išorinis prievadas"</string>
 </resources>
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
index f565157..3bed6cd 100755
--- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml
+++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%Y. gada %-e. %B</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%Y. gada %-e. %b, %H:%M:%S</string>
diff --git a/core/res/res/values-lv/donottranslate-cldr.xml b/core/res/res/values-lv/donottranslate-cldr.xml
index c21481a..7ecdc31 100755
--- a/core/res/res/values-lv/donottranslate-cldr.xml
+++ b/core/res/res/values-lv/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%Y. gada %-e. %B</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y. gada %-e. %b</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1c1f0c5..2c74c82 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lidojuma režīms ir IESLĒGTS."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lidojuma režīms ir IZSLĒGTS."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Iestatījumi"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Balss palīgs"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloķēt tūlīt"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vēlas iespējot funkciju “Atklāt pieskaroties”. Kad ir ieslēgta funkcija “Atklāt pieskaroties”, var dzirdēt vai redzēt tā vienuma aprakstu, virs kura atrodas pirksts, vai veikt žestus, lai mijiedarbotos ar tālruni."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pirms 1 mēneša"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vairāk nekā pirms 1 mēneša"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Pirms 1 sekundes"</item>
-    <item quantity="other" msgid="3903706804349556379">"Pirms <xliff:g id="COUNT">%d</xliff:g> sekundes(-ēm)"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Pirms 1 minūtes"</item>
-    <item quantity="other" msgid="2176942008915455116">"Pirms <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Pirms 1 stundas"</item>
-    <item quantity="other" msgid="2467273239587587569">"Pirms <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Pēdējās <xliff:g id="COUNT">%d</xliff:g> dienās"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Iepriekšējā mēnesī"</string>
     <string name="older" msgid="5211975022815554840">"Vecāks"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"vakar"</item>
-    <item quantity="other" msgid="2479586466153314633">"Pirms <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"pēc 1 sekundes"</item>
-    <item quantity="other" msgid="1241926116443974687">"pēc <xliff:g id="COUNT">%d</xliff:g> sekundes(-ēm)"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"pēc 1 minūtes"</item>
-    <item quantity="other" msgid="3330713936399448749">"pēc <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"pēc 1 stundas"</item>
-    <item quantity="other" msgid="547290677353727389">"pēc <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"rītdien"</item>
-    <item quantity="other" msgid="5109449375100953247">"pēc <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Pirms 1 sekundes"</item>
-    <item quantity="other" msgid="3699169366650930415">"Pirms <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Pirms 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Pirms <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Pirms 1 stundas"</item>
-    <item quantity="other" msgid="6889970745748538901">"Pirms <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"vakar"</item>
-    <item quantity="other" msgid="3453342639616481191">"Pirms <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"pēc 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"pēc <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"pēc 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"pēc <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"pēc 1 stundas"</item>
-    <item quantity="other" msgid="3705373766798013406">"pēc <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"rītdien"</item>
-    <item quantity="other" msgid="2973062968038355991">"pēc <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"šādā datumā: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"šādā gadā: <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Notiek Android palaišana…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Notiek krātuves optimizēšana."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Tiek optimizēta <xliff:g id="NUMBER_0">%1$d</xliff:g>. lietotne no <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Notiek lietotnes <xliff:g id="APPNAME">%1$s</xliff:g> sagatavošana."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Notiek lietotņu palaišana."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Tiek pabeigta sāknēšana."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> darbojas"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s vēlas izveidot savienojumu ar tīklu %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Lietotne %1$s vēlas izveidot savienojumu ar Wi-Fi tīklu %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Lietojumprogramma"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Palaist programmu Wi-Fi Direct. Tādējādi tiks izslēgta Wi-Fi klienta/tīklāja darbība."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS pieprasījums ir mainīts uz DIAL pieprasījumu."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS pieprasījums ir mainīts uz USSD pieprasījumu."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS pieprasījums ir mainīts uz jaunu SS pieprasījumu."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB perifērijas ports"</string>
 </resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index df4b13b..a6ec56c 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режимот на работа во авион е вклучен"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режимот на работа во авион е исклучен"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Поставки"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помош"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заклучи сега"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> сака да овозможи „Истражувај со допир“. Кога е вклучено „Истражувај со допир“, може да се слушнат или да се видат описи на она што е под вашиот прст или да се прават движења за комуницирање со телефонот."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Пред 1 месец"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пред повеќе од 1 месец"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"пред 1 секунда"</item>
-    <item quantity="other" msgid="3903706804349556379">"пред <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"пред 1 минута"</item>
-    <item quantity="other" msgid="2176942008915455116">"пред <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Пред 1 час"</item>
-    <item quantity="other" msgid="2467273239587587569">"пред <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Последните <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Минатиот месец"</string>
     <string name="older" msgid="5211975022815554840">"Постари"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"вчера"</item>
-    <item quantity="other" msgid="2479586466153314633">"Пред <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"за 1 секунда"</item>
-    <item quantity="other" msgid="1241926116443974687">"за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"за 1 минута"</item>
-    <item quantity="other" msgid="3330713936399448749">"за <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"за 1 час"</item>
-    <item quantity="other" msgid="547290677353727389">"за <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"утре"</item>
-    <item quantity="other" msgid="5109449375100953247">"за <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"пред 1 сек"</item>
-    <item quantity="other" msgid="3699169366650930415">"пред <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"пред 1 мин"</item>
-    <item quantity="other" msgid="851164968597150710">"пред <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"пред 1 час"</item>
-    <item quantity="other" msgid="6889970745748538901">"пред <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"вчера"</item>
-    <item quantity="other" msgid="3453342639616481191">"Пред <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"за 1 сек"</item>
-    <item quantity="other" msgid="5495880108825805108">"за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"за 1 мин"</item>
-    <item quantity="other" msgid="4216113292706568726">"за <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"за 1 час"</item>
-    <item quantity="other" msgid="3705373766798013406">"за <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"утре"</item>
-    <item quantity="other" msgid="2973062968038355991">"за <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"на <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"во <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"во <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android стартува…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Оптимизирање на складирањето."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Се оптимизира апликација <xliff:g id="NUMBER_0">%1$d</xliff:g> од <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Се подготвува <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Се стартуваат апликациите."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Подигањето завршува."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> работи"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има слаба конекција на интернет."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s сака да се поврзе на %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликацијата %1$s сака да се поврзе со Wifi-мрежата %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Започни Wi-Fi Direct. Ова ќе го исклучи Wi-Fi клиентот/хточката на пристап."</string>
@@ -1881,4 +1817,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Барањето SS е изменето во барање DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Барањето SS е изменето во барање USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Барањето SS е изменето во ново барање SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Надворешна порта на УСБ"</string>
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index b9bfa99..a2e36ac 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ഫ്ലൈറ്റ് മോഡ് ഓണാണ്"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ഫ്ലൈറ്റ് മോഡ് ഓഫാണ്"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ക്രമീകരണങ്ങൾ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"വോയ്‌സ് സഹായം"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ഇപ്പോൾ ലോക്കുചെയ്യുക"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ടച്ച് വഴി പര്യവേക്ഷണം ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കാൻ <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു. ടച്ച് വഴി പര്യവേക്ഷണം ചെയ്യൽ ഓൺ ചെയ്യുമ്പോൾ, നിങ്ങളുടെ വിരലിനടിയിലുള്ളവയുടെ വിവരണം കേൾക്കാനോ കാണാനോ അല്ലെങ്കിൽ ഫോണുമായി സംവദിക്കുന്ന ജെസ്റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 മാസം മുമ്പുള്ളത്"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ഒരു മാസം മുമ്പ്"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 നിമിഷം മുമ്പ്"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 മിനിറ്റ് മുമ്പ്"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ് മുമ്പ്"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 മണിക്കൂര്‍ മുമ്പ്"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ മുമ്പ്"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"കഴിഞ്ഞ <xliff:g id="COUNT">%d</xliff:g> ദിവസം"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"കഴിഞ്ഞ മാസം"</string>
     <string name="older" msgid="5211975022815554840">"പഴയത്"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ഇന്നലെ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ദിവസം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ഒരു നിമിഷത്തിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷത്തിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ഒരു മിനിറ്റിൽ"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ഒരു മണിക്കൂറിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂറിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"നാളെ"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> ദിവസത്തിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"ഒരു നിമിഷം മുമ്പ്"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"ഒരു മിനിറ്റ് മുമ്പ്"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ് മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 മണിക്കൂര്‍ മുമ്പ്"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ഇന്നലെ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ദിവസം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ഒരു നിമിഷത്തിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷത്തിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ഒരു മിനിറ്റിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ഒരു മണിക്കൂറിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂറിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"നാളെ"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> ദിവസത്തിനുള്ളിൽ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>-ന്"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>-ൽ"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ആരംഭിക്കുന്നു…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"സംഭരണം ഒപ്‌റ്റിമൈസ് ചെയ്യുന്നു."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g> അപ്ലിക്കേഷൻ ഓപ്റ്റിമൈസ് ചെയ്യുന്നു."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> തയ്യാറാക്കുന്നു."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"അപ്ലിക്കേഷനുകൾ ആരംഭിക്കുന്നു."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ബൂട്ട് ചെയ്യൽ പൂർത്തിയാകുന്നു."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> പ്രവർത്തിക്കുന്നു"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്‌റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" മോശം ഇന്റർനെറ്റ് കണക്ഷനാണുള്ളത്."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s, %2$s എന്നതിലേക്ക് കണക്‌റ്റുചെയ്യാൻ ആഗ്രഹിക്കുന്നു"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"അപ്ലിക്കേഷൻ %1$s Wifi നെറ്റ്‌വർക്കിലേക്ക് കണക്‌റ്റുചെയ്യാൻ താൽപ്പര്യപ്പെടുന്നു %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ഒരു അപ്ലിക്കേഷൻ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ഡയറക്‌ട്"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ഡയറക്റ്റ് ആരംഭിക്കുക. ഇത് Wi-Fi ക്ലയന്റ്/ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കും."</string>
@@ -1877,4 +1813,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS അഭ്യർത്ഥന, DIAL അഭ്യർത്ഥനയായി പരിഷ്‌ക്കരിച്ചു."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS അഭ്യർത്ഥന, USSD അഭ്യർത്ഥനയായി പരിഷ്‌ക്കരിച്ചു."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS അഭ്യർത്ഥന, പുതിയ SS അഭ്യർത്ഥനയായി പരിഷ്‌ക്കരിച്ചു."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB പെരിഫറൽ പോർട്ട്"</string>
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index a14588d..d91363a 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Нислэгийн горим асав"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Нислэгийн горим унтарсан"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Тохиргоо"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Дуут туслах"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Одоо түгжих"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрч танихыг идэвхжүүлэхийг шаардаж байна. Хүрч таних идэвхжсэн тохиолдолд та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба утастайгаа дохиогоор харилцах боломжтой."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 сарын өмнө"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 сарын өмнө"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 секундын өмнө"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> секундын өмнө"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 минутын өмнө"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> минутын өмнө"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 цагийн өмнө"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> цагийн өмнө"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Сүүлийн <xliff:g id="COUNT">%d</xliff:g> өдөр"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Сүүлийн сар"</string>
     <string name="older" msgid="5211975022815554840">"Хуучин"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"өчигдөр"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> өдрийн өмнө"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 секундын дараа"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> секундын дараа"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 минутын дараа"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> минутын дараа"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 цагийн дараа"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> цагийн дараа"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"маргааш"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> өдрийн дараа"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 секундын өмнө"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек дараа"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 мин өмнө"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> минутын өмнө"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 цагийн өмнө"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> цагийн өмнө"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"өчигдөр"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> өдрийн өмнө"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 сек дараа"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> сек дараа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 мин дараа"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> минутын дараа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 цагийн дараа"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> цагийн дараа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"маргааш"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> өдрийн дараа"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Андройд эхэлж байна..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Хадгалалтыг сайжруулж байна."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>-н <xliff:g id="NUMBER_0">%1$d</xliff:g> апп-г тохируулж байна."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Бэлдэж байна <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Апп-г эхлүүлж байна."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Эхлэлийг дуусгаж байна."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ажиллаж байна"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет холболт муу байна."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s %2$s-тай холбогдохыг хүсэж байна"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Програм %1$s нь Wifi сүлжээ %2$s-тай холбох хүсэлтэй байна"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Аппликешн"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Шууд"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Шуудыг эхлүүлнэ үү. Энэ нь Wi-Fi клиент/холболтын цэг унтраана."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS хүсэлтийг DIAL хүсэлт болгон өөрчилсөн байна"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS хүсэлтийг USSD хүсэлт болгон өөрчилсөн байна."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS хүсэлтийг шинэ SS хүсэлт болгон өөрчилсөн байна."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 55daa3a..646a29d 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"विमान मोड चालू आहे"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"विमान मोड बंद आहे"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग्ज"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"व्हॉइस सहाय्य"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"आता लॉक करा"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -218,7 +219,7 @@
     <string name="permgroupdesc_location" msgid="5704679763124170100">"आपल्या प्रत्यक्ष स्थानाचे परीक्षण करेल."</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"नेटवर्क संप्रेषण"</string>
     <string name="permgroupdesc_network" msgid="4478299413241861987">"विविध नेटवर्क वैशिष्ट्यांवर प्रवेश करेल."</string>
-    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"ब"</string>
+    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"ब्लूटुथ"</string>
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"ब द्वारे डिव्हाइसेसवर आणि नेटवर्कवर प्रवेश करेल."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"ऑडिओ सेटिंग्ज"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"ऑडिओ सेटिंग्ज बदला."</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा चालू असते, तेव्हा आपण आपल्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा फोनसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 महिन्यापूर्वी"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 महिन्यापूर्वी"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 सेकंदापूर्वी"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांपूर्वी"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 मिनिटापूर्वी"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांपूर्वी"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 तासापूर्वी"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> तासांपूर्वी"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"अंतिम <xliff:g id="COUNT">%d</xliff:g> दिवस"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"अंतिम महिना"</string>
     <string name="older" msgid="5211975022815554840">"अधिक जुने"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"काल"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिवसांपूर्वी"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 सेकंदात"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्‍ये"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 मिनिटात"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांमध्‍ये"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 तासात"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> तासांमध्‍ये"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"उद्या"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिवसांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 सेकंदापूर्वी"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 मिनिटापूर्वी"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 तासापूर्वी"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> तासांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"काल"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिवसांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 सेकंदामध्‍ये"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 मिनिटामध्‍ये"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 तासात"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> तासांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"उद्या"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> दिवसांमध्‍ये"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> रोजी"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> वाजता"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> मध्ये"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android प्रारंभ करत आहे…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"संचयन ऑप्टिमाइझ करत आहे."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> पैकी <xliff:g id="NUMBER_0">%1$d</xliff:g> अॅप ऑप्टिमाइझ करत आहे."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करीत आहे."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"अॅप्स प्रारंभ करत आहे."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त होत आहे."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चालत आहे"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" खराब इंटरनेट कनेक्शन आहे."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s %2$s शी कनेक्ट करू इच्छितात"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s अनुप्रयोग %2$s वायफाय नेटवर्कशी कनेक्ट करू इच्छित आहे"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"अनुप्रयोग"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाय-फाय थेट"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाय-फाय थेट प्रारंभ करा. हे वाय-फाय क्लायंट/हॉटस्पॉट बंद करेल."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS विनंती डायल विनंतीवर सुधारित केली आहे."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS विनंती USSD विनंतीवर सुधारित केली आहे."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS विनंती नवीन SS विनंतीवर सुधारित केली आहे."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB बाह्यवर्ती पोर्ट"</string>
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 7ec40c4..069a6c0 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mod Pesawat DIHIDUPKAN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mod Pesawat DIMATIKAN"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Tetapan"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan telefon."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 saat yang lalu"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saat yang lalu"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minit yang lalu"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minit yang lalu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> hari terakhir"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Bulan lepas"</string>
     <string name="older" msgid="5211975022815554840">"Lebih lama"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"semalam"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dalam 1 saat"</item>
-    <item quantity="other" msgid="1241926116443974687">"dalam <xliff:g id="COUNT">%d</xliff:g> saat"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dalam 1 minit"</item>
-    <item quantity="other" msgid="3330713936399448749">"dalam <xliff:g id="COUNT">%d</xliff:g> minit"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dalam 1 jam"</item>
-    <item quantity="other" msgid="547290677353727389">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"esok"</item>
-    <item quantity="other" msgid="5109449375100953247">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 saat yang lalu"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saat yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minit yang lalu"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minit yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"semalam"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dalam 1 saat"</item>
-    <item quantity="other" msgid="5495880108825805108">"dalam <xliff:g id="COUNT">%d</xliff:g> saat"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dalam 1 minit"</item>
-    <item quantity="other" msgid="4216113292706568726">"dalam <xliff:g id="COUNT">%d</xliff:g> minit"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dalam 1 jam"</item>
-    <item quantity="other" msgid="3705373766798013406">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"esok"</item>
-    <item quantity="other" msgid="2973062968038355991">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"pada <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"dalam <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android sedang dimulakan…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Mengoptimumkan storan."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Mengoptimumkan apl <xliff:g id="NUMBER_0">%1$d</xliff:g> daripada <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Menyediakan <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulakan apl."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"But akhir."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> dijalankan"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ingin menyambung ke %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin menyambung ke Rangkaian Wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Satu aplikasi"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Mulakan Wi-Fi Langsung. Hal ini akan mematikan pengendalian klien/liputan Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Permintaan SS diubah kepada permintaan DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Permintaan SS diubah kepada permintaan USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Permintaan SS diubah kepada permintaan SS baharu."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port Persisian USB"</string>
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 6e0b5ad..c0bea1f 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"လေယဥ်ပျံပေါ်၌အသုံးပြုသောစနစ်ဖွင့်ထားသည်"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"လေယဥ်ပျံပေါ်၌အသုံးပြုသောစနစ်ပိတ်ထားသည်"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ဆက်တင်များ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"အသံ အကူအညီ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ယခု သော့ပိတ်ရန်"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"၉၉၉+"</string>
     <string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> က ထိတွေ့ပြီး ရှာဖွေခြင်းကို လုပ်ချင်ပါသည်။ ထိတွေ့ရှာဖွေခြင်း ဖွင့်ထားလျှင် သင့်လက်ဖျားအောက်မှ အရာကို ကြားနိုင် သို့ ရှင်းလင်းချက်ကို မြင်နိုင်တဲ့ အပြင် လက် အနေအထားဖြင့် ဖုန်းကို ဆက်သွယ်ပြုလုပ်စေခိုင်းနိုင်ပါသည်"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"လွန်ခဲ့သော၁လက"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"လွန်ခဲ့သော၁လမတိုင်မီက"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"လွန်ခဲ့သော ၁စက္ကန့်က"</item>
-    <item quantity="other" msgid="3903706804349556379">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်က"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"လွန်ခဲ့သော ၁မိနစ်က"</item>
-    <item quantity="other" msgid="2176942008915455116">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> မိနစ်က"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"လွနခဲ့သော ၁နာရီက"</item>
-    <item quantity="other" msgid="2467273239587587569">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> နာရီက"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ပြီးခဲ့သော<xliff:g id="COUNT">%d</xliff:g>ရက်က"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"ပြီးခဲ့သောလ"</string>
     <string name="older" msgid="5211975022815554840">"ယခင်က"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"မနေ့က"</item>
-    <item quantity="other" msgid="2479586466153314633">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"နောက် ၁စက္ကန့်တွင်"</item>
-    <item quantity="other" msgid="1241926116443974687">"နောက် <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်တွင်"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"နောက်၁မီနစ်တွင်"</item>
-    <item quantity="other" msgid="3330713936399448749">"နောက် <xliff:g id="COUNT">%d</xliff:g> မိနစ်တွင်"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"နောက်၁နာရီတွင်"</item>
-    <item quantity="other" msgid="547290677353727389">"နောက် <xliff:g id="COUNT">%d</xliff:g> နာရီတွင်"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"မနက်ဖြန်"</item>
-    <item quantity="other" msgid="5109449375100953247">"နောက် <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"လွန်ခဲ့သော ၁စက္ကန့်က"</item>
-    <item quantity="other" msgid="3699169366650930415">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်က"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"လွန်ခဲ့သော ၁မိနစ်က"</item>
-    <item quantity="other" msgid="851164968597150710">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> မိနစ်က"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"လွန်ခဲ့သော ၁နာရီက"</item>
-    <item quantity="other" msgid="6889970745748538901">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> နာရီက"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"မနေ့က"</item>
-    <item quantity="other" msgid="3453342639616481191">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"နောက် ၁စက္ကန့်တွင်"</item>
-    <item quantity="other" msgid="5495880108825805108">"နောက် <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"နောက်၁မိနစ်တွင်"</item>
-    <item quantity="other" msgid="4216113292706568726">"နောက် <xliff:g id="COUNT">%d</xliff:g> မိနစ်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"နောက်၁နာရီတွင်"</item>
-    <item quantity="other" msgid="3705373766798013406">"နောက် <xliff:g id="COUNT">%d</xliff:g> နာရီတွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"မနက်ဖြန်"</item>
-    <item quantity="other" msgid="2973062968038355991">"နောက် <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> တွင်"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>မှာ"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>တွင်"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android စတင်နေ…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"သိုလှောင်မှုအား ပြုပြင်ခြင်း။"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> ထဲက app<xliff:g id="NUMBER_1">%2$d</xliff:g>ကို ဆီလျော်အောင် လုပ်နေ"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> အားပြင်ဆင်နေသည်။"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"appများကို စတင်နေ"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"လုပ်ငန်းစနစ်ထည့်သွင်း၍ ပြန်လည်စတင်ရန် ပြီးပါပြီ"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> က အလုပ်လုပ်နေသည်"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" အင်တာနက် ဆက်သွယ်မှု ကောင်းကောင်းမရှိပါ"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s က %2$s သို့ ချိတ်ဆက်ချင်"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"အပ္ပလီကေးရှင်း %1$s သည် ဝိုင်ဖိုင်ကွန်ရက် %2$s ကိုချိတ်ဆက်လိုသည်"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"အပလီကေးရှင်း"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"တိုက်ရိုက် ဝိုင်ဖိုင်"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"တိုက်ရိုက်ဝိုင်ဖိုင်ကို စတင်ပါ။ ၎င်းသည် ဝိုင်ဖိုင် ဟော့စပေါ့ကို ရပ်ဆိုင်းစေမှာ ဖြစ်ပါသည်။"</string>
@@ -1877,4 +1813,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"DIAL တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"USSD တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"အန်းဒရွိုက်"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB ဘေးရှိပို့တ်"</string>
 </resources>
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
index 3b2a6c6..17aea0e 100755
--- a/core/res/res/values-nb/donottranslate-cldr.xml
+++ b/core/res/res/values-nb/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e. %b %Y</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index dc38563..1b14de1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Innstillinger"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Talehjelp"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nå"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ber om aktivering av Utforsk ved å trykke. Når Utforsk ved å trykke er slått på, kan du høre eller se beskrivelser av det som er under fingrene dine. Du kan også utføre handlinger på nettbrettet ved hjelp av bevegelser."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"For én måned siden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"For over en måned siden"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"for et sekund siden"</item>
-    <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"for et minutt siden"</item>
-    <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"for en time siden"</item>
-    <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Siste <xliff:g id="COUNT">%d</xliff:g> dager"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Forrige måned"</string>
     <string name="older" msgid="5211975022815554840">"Eldre"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"i går"</item>
-    <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"om et sekund"</item>
-    <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"om et minutt"</item>
-    <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"om et minutt"</item>
-    <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sek siden"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min siden"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 t siden"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"i går"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"om 1 sek"</item>
-    <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"om 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"om 1 t"</item>
-    <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"i <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android starter …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimaliser lagring."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimaliserer app <xliff:g id="NUMBER_0">%1$d</xliff:g> av <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Forbereder <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starter apper."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Ferdigstiller oppstart."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s prøver å koble til %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vil koble til Wi-Fi-nettverket %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette deaktiverer Wi-Fi-klienten/-sonen."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-forespørselen er endret til en RINGE-forespørsel."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-forespørselen er endret til en USSD-forespørsel."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-forespørselen er endret til en ny SS-forespørsel."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port for USB-tilleggsutstyr"</string>
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index fb8e1c2..da70149 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाइजहाज मोड खुला छ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाइजहाज मोड बन्द छ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"सेटिङ्हरू"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज सहायता"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"अब बन्द गर्नुहोस्"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>ले स्पर्षद्वारा अन्वेषण सक्षम गर्न चाहन्छ। स्पर्षद्वारा अन्वेषण सक्षम भएको बेला तपाईँ आफ्नो औँलाको मुनि भएका विषयवस्तुहरू बारे सुन्न वा विवरण हेर्न सक्नुहुन्छ वा फोनसँग अन्तर्क्रिया गर्न इशारा गर्नुहोस्।"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"१ महिना अघि"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"१ महिना अघि"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"१ सेकेन्ड अघि"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड अघि"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"१ मिनेट अघि"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनेट अघि"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"१ घन्टा अघि"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> घन्टा अघि"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"अन्तिम <xliff:g id="COUNT">%d</xliff:g> दिन"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"अन्तिम महिना"</string>
     <string name="older" msgid="5211975022815554840">"पुरानो"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"हिजो"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिन अघि"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"१ सेकेन्डमा"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"१ मिनेटमा"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>मिनेटमा"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"१ घन्टामा"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> घन्टामा"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"भोलि"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिनमा"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"१ सेकेन्ड अघि"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड अगाडि"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"१ मिनेट अघि"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनेट अघि"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"१ घन्टा अघि"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> घन्टा अघि"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"हिजो"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिन अघि"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"१ सेकन्ड"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"१ मिनेटमा"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनेटमा"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"१ घन्टामा"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> घन्टामा"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"भोलि"</item>
-    <item quantity="other" msgid="2973062968038355991">"दिन<xliff:g id="COUNT">%d</xliff:g> मा"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> मा"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> मा"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> मा"</string>
@@ -1309,6 +1244,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android शुरू हुँदैछ..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"भण्डारण अनुकूलन गर्दै।"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"अनुप्रयोग अनुकुल हुँदै <xliff:g id="NUMBER_0">%1$d</xliff:g> को <xliff:g id="NUMBER_1">%2$d</xliff:g>।"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयारी गर्दै।"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"सुरुवात अनुप्रयोगहरू।"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"बुट पुरा हुँदै।"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string>
@@ -1354,7 +1290,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" कमजोर इन्टरनेट जडान छ।"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ले %2$s मा जडान गर्न चाहन्छ"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"अनुप्रयोग %1$s Wifi सञ्जाल %2$s मा जडान गर्न चाहन्छ"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"एउटा अनुप्रयोग"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाइफाइ प्रत्यक्ष"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाइफाइ सिधा सुरु गर्नुहोस्। यसले वाइफाइ ग्राहक/हट्स्पटलाई बन्द गराउने छ।"</string>
@@ -1885,4 +1821,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS अनुरोध  DIAL अनुरोधमा परिमार्जन गरिएको छ।"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS अनुरोध USSD अनुरोधमा परिमार्जन गरिएको छ।"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS अनुरोध नयाँ SS अनुरोधमा परिमार्जन गरिएको छ।"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB परिधीय पोर्ट"</string>
 </resources>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
new file mode 100644
index 0000000..da870b7
--- /dev/null
+++ b/core/res/res/values-night/themes_material_daynight.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+
+    <!-- Material theme (day/night version) for activities. -->
+    <style name="Theme.Material.DayNight" parent="Theme.Material" />
+
+    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
+         with an inverse color profile. The dark action bar sharply stands out against
+         the light content (when applicable).  -->
+    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
+
+    <!-- Variant of Material.DayNight with no action bar.  -->
+    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen. This theme
+         sets {@link android.R.attr#windowFullscreen} to true.  -->
+    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen and extends into the display overscan region. This theme
+         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+         to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
+
+    <!-- Variant of Material.DayNight that has no title bar and translucent
+         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+         {@link android.R.attr#windowTranslucentNavigation} to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
+
+    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
+         window decorations, so you basically have an empty rectangle in which
+         to place your content. It makes the window floating, with a transparent
+         background, and turns off dimming behind the window. -->
+    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
+
+    <!-- Material theme (day/night version) for dialog windows and activities,
+         which is used by the {@link android.app.Dialog} class. This changes
+         the window to be floating (not fill the entire screen), and puts a
+         frame around its contents. You can set this theme on an activity if
+         you would like to make an activity that looks like a Dialog. -->
+    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
+    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
+
+    <!-- Theme for a window that will be displayed either full-screen on
+         smaller screens (small, normal) or as a dialog on larger screens
+         (large, xlarge). -->
+    <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
+
+    <!-- Theme for a window without an action bar that will be displayed either full-screen
+         on smaller screens (small, normal) or as a dialog on larger screens
+         (large, xlarge). -->
+    <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
+
+    <!-- Theme for a presentation window on a secondary display. -->
+    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
+
+    <!-- Material user theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class. -->
+    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
+    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
+
+    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
+    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
+
+</resources>
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
index 29b120c..35a84eb 100755
--- a/core/res/res/values-nl/donottranslate-cldr.xml
+++ b/core/res/res/values-nl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 75f4a74..c4bb334 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil \'Verkennen via aanraking\' inschakelen. Wanneer \'Verkennen via aanraking\' is ingeschakeld, kunt u beschrijvingen beluisteren of bekijken van wat er onder uw vinger staat of aanraakbewerkingen uitvoeren op de telefoon."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand geleden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Meer dan 1 maand geleden"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 seconde geleden"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuut geleden"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 uur geleden"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Afgelopen <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Afgelopen maand"</string>
     <string name="older" msgid="5211975022815554840">"Ouder"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"gisteren"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"over 1 seconde"</item>
-    <item quantity="other" msgid="1241926116443974687">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"over 1 minuut"</item>
-    <item quantity="other" msgid="3330713936399448749">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"over 1 uur"</item>
-    <item quantity="other" msgid="547290677353727389">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 seconde geleden"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minuut geleden"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 uur geleden"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"gisteren"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"over 1 seconde"</item>
-    <item quantity="other" msgid="5495880108825805108">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"over 1 minuut"</item>
-    <item quantity="other" msgid="4216113292706568726">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"over 1 uur"</item>
-    <item quantity="other" msgid="3705373766798013406">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android wordt gestart…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Opslagruimte wordt geoptimaliseerd."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> van <xliff:g id="NUMBER_1">%2$d</xliff:g> optimaliseren."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> voorbereiden."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Apps starten."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Opstarten afronden."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s wilt verbinding maken met %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"App %1$s wil verbinding maken met wifi-netwerk %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Een app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wifi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wifi Direct starten. Hierdoor wordt de wifi-client/hotspot uitgeschakeld."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-verzoek is gewijzigd in DIAL-verzoek."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-verzoek is gewijzigd in USSD-verzoek."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-verzoek is gewijzigd in nieuw SS-verzoek."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Poort voor USB-randapparatuur"</string>
 </resources>
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
index f9431b2..3f341b8 100755
--- a/core/res/res/values-pl/donottranslate-cldr.xml
+++ b/core/res/res/values-pl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d.%m.%Y %H:%M:%S</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 2482b0a..ac14db8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ustawienia"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asystent głosowy"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zablokuj teraz"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
@@ -269,13 +270,13 @@
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Dostęp do karty SD."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Funkcje ułatwień dostępu"</string>
     <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Funkcje, których może zażądać technologia ułatwień dostępu."</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pobierz zawartość okna"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pobieranie zawartości okna"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Sprawdzanie zawartości okna, z którego korzystasz."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Włącz czytanie dotykiem"</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Włączenie czytania dotykiem"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Klikane elementy będą wymawiane na głos, a ekran można przeglądać, używając gestów."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Włącz ułatwienia dostępu w internecie"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Włączenie ułatwień dostępu w internecie"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Można zainstalować skrypty, by zawartość aplikacji była łatwiej dostępna."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Obserwuj wpisywany tekst"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Obserwowanie wpisywanego tekstu"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obejmuje informacje osobiste, takie jak numery kart kredytowych i hasła."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string>
@@ -1130,77 +1131,11 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> chce włączyć Czytanie dotykiem. Gdy ta funkcja jest włączona, słyszysz i widzisz opisy elementów, które są pod Twoim palcem, oraz możesz obsługiwać telefon gestami."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiąc temu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiąc temu"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"sekundę temu"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minutę temu"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"godzinę temu"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Ostatnie (<xliff:g id="COUNT">%d</xliff:g>) dni"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Ostatni miesiąc"</string>
     <string name="older" msgid="5211975022815554840">"Starsze"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"wczoraj"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"za sekundę"</item>
-    <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"za minutę"</item>
-    <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"za godzinę"</item>
-    <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"jutro"</item>
-    <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"sekundę temu"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> s temu"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"minutę temu"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"godzinę temu"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"wczoraj"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"za sekundę"</item>
-    <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za minutę"</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"za godzinę"</item>
-    <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"jutro"</item>
-    <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"w dniu <xliff:g id="DATE">%s</xliff:g>"</string>
-    <string name="preposition_for_time" msgid="5506831244263083793">"o godzinie <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="preposition_for_time" msgid="5506831244263083793">"o godzinie <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"w <xliff:g id="YEAR">%s</xliff:g> r."</string>
     <string name="day" msgid="8144195776058119424">"dzień"</string>
     <string name="days" msgid="4774547661021344602">"dni"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android się uruchamia…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optymalizacja pamięci."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optymalizowanie aplikacji <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Przygotowuję aplikację <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Uruchamianie aplikacji."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Kończenie uruchamiania."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Działa <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s chce połączyć się z: %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacja %1$s chce połączyć się z siecią Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacja"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Uruchom Wi-Fi Direct. Spowoduje to wyłączenie klienta lub punktu dostępu Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Żądanie SS zostało zmienione na żądanie DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Żądanie SS zostało zmienione na żądanie USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Żądanie SS zostało zmienione na nowe żądanie SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port peryferyjny USB"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index 9c9f903..6355432 100755
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e de %b de %Y</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 40e9313..87c4dcc 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está ativado"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desativado"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Definições"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> pretende ativar a funcionalidade Explorar Através do Toque. Quando a funcionalidade Explorar Através do Toque estiver ativada, pode ouvir ou visualizar descrições sobre o que está por baixo do seu dedo ou executar gestos para interagir com o telemóvel."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Há 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Há 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Há 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Último mês"</string>
     <string name="older" msgid="5211975022815554840">"Mais antiga"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ontem"</item>
-    <item quantity="other" msgid="2479586466153314633">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"daqui a 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"daqui a 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"daqui a 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
-    <item quantity="other" msgid="5109449375100953247">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Há 1 seg"</item>
-    <item quantity="other" msgid="3699169366650930415">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"há 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Há 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ontem"</item>
-    <item quantity="other" msgid="3453342639616481191">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"daqui a 1 seg"</item>
-    <item quantity="other" msgid="5495880108825805108">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"daqui a 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"daqui a 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
-    <item quantity="other" msgid="2973062968038355991">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"a <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"às <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"em <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"O Android está a iniciar…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"A otimizar o armazenamento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"A otimizar a aplicação <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"A preparar o <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"A iniciar aplicações"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"A concluir o arranque."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s pretende ligar a %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicação %1$s pretende estabelecer ligação à rede Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Uma aplicação"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Esta opção desativará o cliente/zona Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"O pedido SS foi modificado para um pedido DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"O pedido SS foi modificado para um pedido USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"O pedido SS foi modificado para um novo pedido SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porta periférica USB"</string>
 </resources>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 2da7599..c97b337 100755
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %d/%m/%Y</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a11ba9d..f65b088 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configurações"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar a exploração pelo toque. Com ela, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone através de gestos."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 segundo atrás"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuto atrás"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 hora atrás"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Mês passado"</string>
     <string name="older" msgid="5211975022815554840">"Mais antigos"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ontem"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"em 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"em 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"em 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
-    <item quantity="other" msgid="5109449375100953247">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 seg. atrás"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> segundos   atrás"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minuto atrás"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 hora atrás"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ontem"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"em 1 segundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"em 1 minuto"</item>
-    <item quantity="other" msgid="4216113292706568726">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"em 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
-    <item quantity="other" msgid="2973062968038355991">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"em <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"às <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"em <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"O Android está iniciando..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Otimizando o armazenamento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Otimizando app <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Concluindo a inicialização."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s gostaria de se conectar a %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"O app %1$s deseja se conectar à rede Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Um app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitação SS foi modificada para a solicitação DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitação SS foi modificada para a solicitação USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitação SS foi modificada para a nova solicitação SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porta USB periférica"</string>
 </resources>
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
index cfb79e8..c874dcf 100755
--- a/core/res/res/values-ro-rRO/donottranslate-cldr.xml
+++ b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ro/donottranslate-cldr.xml b/core/res/res/values-ro/donottranslate-cldr.xml
index cfb79e8..c874dcf 100755
--- a/core/res/res/values-ro/donottranslate-cldr.xml
+++ b/core/res/res/values-ro/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 625f720..018d3b0 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Setări"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu telefonul."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"cu 1 secundă în urmă"</item>
-    <item quantity="other" msgid="3903706804349556379">"cu <xliff:g id="COUNT">%d</xliff:g> (de) secunde în urmă"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"cu 1 minut în urmă"</item>
-    <item quantity="other" msgid="2176942008915455116">"cu <xliff:g id="COUNT">%d</xliff:g> (de) minute în urmă"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"cu 1 oră în urmă"</item>
-    <item quantity="other" msgid="2467273239587587569">"cu <xliff:g id="COUNT">%d</xliff:g> (de) ore în urmă"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Ultimele <xliff:g id="COUNT">%d</xliff:g> de zile"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Luna trecută"</string>
     <string name="older" msgid="5211975022815554840">"Mai vechi"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ieri"</item>
-    <item quantity="other" msgid="2479586466153314633">"cu <xliff:g id="COUNT">%d</xliff:g> (de) zile în urmă"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"într-o secundă"</item>
-    <item quantity="other" msgid="1241926116443974687">"în <xliff:g id="COUNT">%d</xliff:g> (de) secunde"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"în 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"în <xliff:g id="COUNT">%d</xliff:g> (de) minute"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"în 1 oră"</item>
-    <item quantity="other" msgid="547290677353727389">"în <xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mâine"</item>
-    <item quantity="other" msgid="5109449375100953247">"în <xliff:g id="COUNT">%d</xliff:g> (de) zile"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"cu 1 sec. în urmă"</item>
-    <item quantity="other" msgid="3699169366650930415">"cu <xliff:g id="COUNT">%d</xliff:g> (de) secunde în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"cu 1 min. în urmă"</item>
-    <item quantity="other" msgid="851164968597150710">"cu <xliff:g id="COUNT">%d</xliff:g> (de) min. în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"cu 1 oră în urmă"</item>
-    <item quantity="other" msgid="6889970745748538901">"cu <xliff:g id="COUNT">%d</xliff:g> (de) ore în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ieri"</item>
-    <item quantity="other" msgid="3453342639616481191">"cu <xliff:g id="COUNT">%d</xliff:g> (de) zile în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"în 1 sec."</item>
-    <item quantity="other" msgid="5495880108825805108">"în <xliff:g id="COUNT">%d</xliff:g> (de) sec."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"în 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"în <xliff:g id="COUNT">%d</xliff:g> (de) min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"în 1 oră"</item>
-    <item quantity="other" msgid="3705373766798013406">"în <xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mâine"</item>
-    <item quantity="other" msgid="2973062968038355991">"în <xliff:g id="COUNT">%d</xliff:g> (de) zile"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"pe <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"la <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"în <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android pornește..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Se optimizează stocarea."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Se optimizează aplicaţia <xliff:g id="NUMBER_0">%1$d</xliff:g> din <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Se pregătește <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Se pornesc aplicaţiile."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Se finalizează pornirea."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s dorește să se conecteze la %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplicația %1$s dorește să se conecteze la rețeaua Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"O aplicație"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Solicitarea SS este modificată într-o solicitare DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Solicitarea SS este modificată într-o solicitare USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Solicitarea SS este modificată într-o nouă solicitare SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB periferic"</string>
 </resources>
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
index c22df99..a36f13d 100755
--- a/core/res/res/values-ru/donottranslate-cldr.xml
+++ b/core/res/res/values-ru/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y г.</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a768aa9..c613d55 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хочет включить функцию \"Аудиоподсказки\". Она позволяет прослушивать или просматривать описание элементов, которых вы касаетесь, и управлять телефоном с помощью жестов."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц назад"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более месяца назад"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 секунду назад"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> с. назад"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 минуту назад"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 час назад"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Последние <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Прошлый месяц"</string>
     <string name="older" msgid="5211975022815554840">"Еще раньше"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"вчера"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"через 1 секунду"</item>
-    <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"через 1 минуту"</item>
-    <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"через 1 час"</item>
-    <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"завтра"</item>
-    <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 сек. назад"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. назад"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 мин. назад"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 час назад"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"вчера"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
-    <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"через 1 мин."</item>
-    <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"через 1 час"</item>
-    <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"завтра"</item>
-    <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"в <xliff:g id="YEAR">%s</xliff:g> г."</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Запуск Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Оптимизация хранилища…"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимизация приложения <xliff:g id="NUMBER_0">%1$d</xliff:g> из <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Подготовка приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"..."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск приложений."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Окончание загрузки..."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Приложение <xliff:g id="APP">%1$s</xliff:g> запущено"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s запрашивает доступ на подключение к %2$s."</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложение \"%1$s\" запрашивает доступ на подключение к сети Wi-Fi (%2$s)"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Начать соединение через Wi-Fi Direct. Модуль Wi-Fi будет отключен."</string>
@@ -1846,7 +1782,7 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запрашивать PIN-код для отключения блокировки"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запрашивать графический ключ для отключения блокировки"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запрашивать пароль для отключения блокировки"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы заряд батареи расходовался медленнее, режим энергосбережения уменьшает быстродействие устройства и ограничивает количество ресурсов, затрачиваемых на вибрацию, Геолокацию и большинство процессов обработки данных в фоновом режиме. Приложения, которые используют синхронизацию (например, для электронной почты и обмена SMS), могут не обновляться, пока вы их не откроете.\n\nКогда устройство заряжается, режим энергосбережения отключается автоматически."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибрации, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только когда вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"До отключения режима (в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До отключения режима"</string>
   <plurals name="zen_mode_duration_minutes_summary">
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-запрос преобразован в DIAL-запрос."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-запрос преобразован в USSD-запрос."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-запрос преобразован в новый SS-запрос."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Внешний USB-порт"</string>
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 3cde8f6..af55f75 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"අහස්යානා ආකාරය සක්‍රීයයි."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"අහස්යානා අකාරය අක්‍රියයි"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"සැකසීම්"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"හඬ සහායක"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"දැන් අගුළු දමන්න"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"ආරක්‍ෂිත ආකාරය"</string>
@@ -1132,75 +1133,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ස්පර්ශය වෙතින් ගවේෂණය සක්‍රිය කිරීමට <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ට අවශ්‍යයි. ස්පර්ශය වෙතින් ගවේෂණය සක්‍රිය විට, ඔබගේ ඇඟිලිවලට පහළ විස්තර ඇසිය හෝ බැලිය හැක හෝ දුරකථනය සමග අන්තර් ක්‍රියාකාරී වීමට ඉංගිති සිදු කළ හැක."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"මාස 1 කට පෙර"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"මාස 1 කට පෙර"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"තත්පර 1 කට පෙර"</item>
-    <item quantity="other" msgid="3903706804349556379">"තත්පර <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"මිනිත්තු 1 ට පෙර"</item>
-    <item quantity="other" msgid="2176942008915455116">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"පැය 1 කට පෙර"</item>
-    <item quantity="other" msgid="2467273239587587569">"පැය <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"අන්තිම දවස් <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"අවසාන මාසය"</string>
     <string name="older" msgid="5211975022815554840">"පරණ"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ඊයේ"</item>
-    <item quantity="other" msgid="2479586466153314633">"දින <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"තත්පර 1 කින්"</item>
-    <item quantity="other" msgid="1241926116443974687">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කදී"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"මිනිත්තු 1 කදී"</item>
-    <item quantity="other" msgid="3330713936399448749">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"පැය 1 ක් තුළ"</item>
-    <item quantity="other" msgid="547290677353727389">"පැය <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"හෙට"</item>
-    <item quantity="other" msgid="5109449375100953247">"දින <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"තත්පර 1 කට පෙර"</item>
-    <item quantity="other" msgid="3699169366650930415">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"මිනිත්තු 1 කට පෙර"</item>
-    <item quantity="other" msgid="851164968597150710">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"පැය 1 කට පෙර"</item>
-    <item quantity="other" msgid="6889970745748538901">"පැය <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ඊයේ"</item>
-    <item quantity="other" msgid="3453342639616481191">"දින <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"තත්පර 1 ක් තුළ"</item>
-    <item quantity="other" msgid="5495880108825805108">"තත්පර <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"මිනිත්තු 1 ක් තුළ"</item>
-    <item quantity="other" msgid="4216113292706568726">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"පැය 1 ක් තුළ"</item>
-    <item quantity="other" msgid="3705373766798013406">"පැය <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"හෙට"</item>
-    <item quantity="other" msgid="2973062968038355991">"දින <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> වන දා"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> ට"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> තුළ"</string>
@@ -1305,6 +1240,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ආරම්භ කරමින්…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ආචයනය ප්‍රශස්තිකරණය කිරීම."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> කින් <xliff:g id="NUMBER_0">%1$d</xliff:g> වැනි යෙදුම ප්‍රශස්ත කරමින්."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> සූදානම් කරමින්."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"යෙදුම් ආරම්භ කරමින්."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ඇරඹුම අවසාන කරමින්."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string>
@@ -1350,7 +1286,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" දුබල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%2$s වෙත සම්බන්ධවීමට %1$s කැමතිය"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"යෙදුම් %1$s ක් WiFi ජාලය %2$s වෙත සම්බන්ධ කිරීමට කැමතියි"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"යෙදුම"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ඍජු Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ඍජු Wi-Fi ආරම්භ කරන්න. මෙය Wi-Fi සේවාදායක/හොට්ස්පොට් එක අක්‍රිය කරනු ඇත."</string>
@@ -1881,4 +1817,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ඉල්ලීම DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ඉල්ලීම USSD ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ඉල්ලීම නව DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB පර්යන්ත තොට"</string>
 </resources>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index 765c51e..51f7e38 100755
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %-e. %-m. %Y</string>
diff --git a/core/res/res/values-sk/donottranslate-cldr.xml b/core/res/res/values-sk/donottranslate-cldr.xml
index d4953c3..b30fe97 100755
--- a/core/res/res/values-sk/donottranslate-cldr.xml
+++ b/core/res/res/values-sk/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4b56f04..312791b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim v lietadle je ZAPNUTÝ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim v lietadle je VYPNUTÝ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nastavenia"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlasový asistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Uzamknúť"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
@@ -703,7 +704,7 @@
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Umožňuje aplikácii zobraziť informácie o sieťach Wi-Fi. Napríklad o tom, či je sieť Wi-Fi povolená alebo názvy pripojených zariadení Wi-Fi."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"pripojiť a odpojiť od siete Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Umožňuje aplikácii pripojiť sa na prístupové body siete Wi-Fi, odpojiť sa od nich a meniť konfiguráciu zariadení pre siete Wi-Fi."</string>
-    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Povoliť príjem viacsmerového vysielania Wi-Fi"</string>
+    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"povoliť príjem Wi-Fi Multicast"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Umožňuje aplikácii prijímať pakety odoslané na všetky zariadenia v sieti Wi-Fi pomocou viacsmerových adries, nielen pomocou vášho tabletu. Spotrebuje viac energie ako režim bez viacsmerového vysielania."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Umožňuje aplikácii prijímať pakety odosielané na všetky zariadenia v sieti Wi-Fi pomocou viacsmerových adries (a nie iba do vášho televízora). Spotrebúva viac energie ako režim bez viacsmerového vysielania."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Umožňuje aplikácii prijímať pakety odoslané na všetky zariadenia v sieti Wi-Fi pomocou viacsmerových adries, nielen pomocou vášho telefónu. Spotrebuje viac energie ako režim bez viacsmerového vysielania."</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Služba <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> požaduje povolenie funkcie Preskúmanie dotykom. Ak je funkcia Preskúmanie dotykom zapnutá, môžete počuť alebo vidieť popisy objektov pod vaším prstom alebo ovládať telefón gestami."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"pred 1 mesiacom"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Viac ako pred 1 mesiacom"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"pred 1 sekundou"</item>
-    <item quantity="other" msgid="3903706804349556379">"pred <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Pred minútou"</item>
-    <item quantity="other" msgid="2176942008915455116">"pred <xliff:g id="COUNT">%d</xliff:g> minútami"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"pred 1 hodinou"</item>
-    <item quantity="other" msgid="2467273239587587569">"pred <xliff:g id="COUNT">%d</xliff:g> hodinami"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Posledných <xliff:g id="COUNT">%d</xliff:g> dní"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Minulý mesiac"</string>
     <string name="older" msgid="5211975022815554840">"Staršie"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"včera"</item>
-    <item quantity="other" msgid="2479586466153314633">"pred <xliff:g id="COUNT">%d</xliff:g> dňami"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"o 1 sekundu"</item>
-    <item quantity="other" msgid="1241926116443974687">"o <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"o 1 minútu"</item>
-    <item quantity="other" msgid="3330713936399448749">"o <xliff:g id="COUNT">%d</xliff:g> minút"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"o 1 hodinu"</item>
-    <item quantity="other" msgid="547290677353727389">"o <xliff:g id="COUNT">%d</xliff:g> hodín"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"zajtra"</item>
-    <item quantity="other" msgid="5109449375100953247">"o <xliff:g id="COUNT">%d</xliff:g> dní"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"pred 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"pred <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"pred 1 min."</item>
-    <item quantity="other" msgid="851164968597150710">"pred <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"pred 1 hodinou"</item>
-    <item quantity="other" msgid="6889970745748538901">"pred <xliff:g id="COUNT">%d</xliff:g> hodinami"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"včera"</item>
-    <item quantity="other" msgid="3453342639616481191">"pred <xliff:g id="COUNT">%d</xliff:g> dňami"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"o 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"o <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"o 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"o <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"o 1 hodinu"</item>
-    <item quantity="other" msgid="3705373766798013406">"o <xliff:g id="COUNT">%d</xliff:g> hodín"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"zajtra"</item>
-    <item quantity="other" msgid="2973062968038355991">"o <xliff:g id="COUNT">%d</xliff:g> dní"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dňa <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"z <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Systém Android sa spúšťa…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimalizuje sa úložisko"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Prebieha optimalizácia aplikácie <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Pripravuje sa aplikácia <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Prebieha spúšťanie aplikácií."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Prebieha dokončovanie spúšťania."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Spustená aplikácia: <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"Zariadenie %1$s sa chce pripojiť k sieti %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikácia %1$s sa chce pripojiť k sieti Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikácia"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustiť priame pripojenie siete Wi-Fi. Táto možnosť vypne sieť Wi-Fi v režime klient alebo hotspot."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Žiadosť SS bola upravená na žiadosť DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Žiadosť SS bola upravená na žiadosť USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Žiadosť SS bola upravená na novú žiadosť SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB pre periférne zariadenia"</string>
 </resources>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index 17d8609..798f4c0 100755
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%d. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %-e. %b %Y</string>
diff --git a/core/res/res/values-sl/donottranslate-cldr.xml b/core/res/res/values-sl/donottranslate-cldr.xml
index 83e4693..92cd963 100755
--- a/core/res/res/values-sl/donottranslate-cldr.xml
+++ b/core/res/res/values-sl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%d. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e. %b. %Y</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index dca7d4e..df365fd 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Način za letalo je VKLOPLJEN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Način za letalo je IZKLOPLJEN"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nastavitve"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Glas. pomočnik"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zakleni zdaj"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Storitev <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogočiti raziskovanje z dotikom. Ko je raziskovanje z dotikom vklopljeno, lahko slišite ali vidite opise tega, kar je pod vašim prstom, ali izvajate poteze za interakcijo s telefonom."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pred 1 mesecem"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Pred več kot 1 mesecem"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Pred 1 sekundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"pred toliko sekundami: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"pred 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"Pred <xliff:g id="COUNT">%d</xliff:g> minutami"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"pred 1 uro"</item>
-    <item quantity="other" msgid="2467273239587587569">"Pred <xliff:g id="COUNT">%d</xliff:g> urami"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Zadnjih <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Pretekli mesec"</string>
     <string name="older" msgid="5211975022815554840">"Starejše"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"včeraj"</item>
-    <item quantity="other" msgid="2479586466153314633">"Pred <xliff:g id="COUNT">%d</xliff:g> dnevi"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"čez 1 sekundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"Čez <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"čez 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"Čez toliko minut: <xliff:g id="COUNT">%d</xliff:g>."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"čez 1 uro"</item>
-    <item quantity="other" msgid="547290677353727389">"čez <xliff:g id="COUNT">%d</xliff:g> ur"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"jutri"</item>
-    <item quantity="other" msgid="5109449375100953247">"čez <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"pred 1 sekundo"</item>
-    <item quantity="other" msgid="3699169366650930415">"Pred toliko sekundami: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"pred 1 minuto"</item>
-    <item quantity="other" msgid="851164968597150710">"Pred <xliff:g id="COUNT">%d</xliff:g> minutami"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"pred 1 uro"</item>
-    <item quantity="other" msgid="6889970745748538901">"Pred <xliff:g id="COUNT">%d</xliff:g> urami"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"včeraj"</item>
-    <item quantity="other" msgid="3453342639616481191">"Pred <xliff:g id="COUNT">%d</xliff:g> dnevi"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"čez 1 sekundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"čez toliko sekund: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"čez 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"čez <xliff:g id="COUNT">%d</xliff:g> minut"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"čez 1 uro"</item>
-    <item quantity="other" msgid="3705373766798013406">"čez <xliff:g id="COUNT">%d</xliff:g> ur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"jutri"</item>
-    <item quantity="other" msgid="2973062968038355991">"čez <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"vsak <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ob <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"leta <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android se zaganja …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimiziranje shrambe."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Pripravljanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Zagon aplikacij."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončevanje zagona."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> se izvaja"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s želi vzpostaviti povezavo s tem: %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi vzpostaviti povezavo z omrežjem Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Zaženite Wi-Fi Direct. S tem boste izklopili odjemalca/dostopno točko Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Zahteva SS je spremenjena v zahtevo DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Zahteva SS je spremenjena v zahtevo USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Zahteva SS je spremenjena v novo zahtevo SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Zunanja vrata USB"</string>
 </resources>
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
index 8bb5fa7f1..a0f4bc2 100755
--- a/core/res/res/values-sr-rRS/donottranslate-cldr.xml
+++ b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%d. %B %Y.</string>
     <string name="time_of_day">%H.%M.%S</string>
     <string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
diff --git a/core/res/res/values-sr/donottranslate-cldr.xml b/core/res/res/values-sr/donottranslate-cldr.xml
index 8bb5fa7f1..a0f4bc2 100755
--- a/core/res/res/values-sr/donottranslate-cldr.xml
+++ b/core/res/res/values-sr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%d. %B %Y.</string>
     <string name="time_of_day">%H.%M.%S</string>
     <string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index de9029f..8277f33 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим рада у авиону је УКЉУЧЕН"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим рада у авиону је ИСКЉУЧЕН"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Подешавања"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помоћ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Закључај одмах"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> жели да омогући Истраживање додиром. Када је Истраживање додиром укључено, можете да чујете или видите описе ставке на коју сте ставили прст или да комуницирате са телефоном помоћу покрета."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Пре месец дана"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пре месец дана"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Пре 1 секунде"</item>
-    <item quantity="other" msgid="3903706804349556379">"пре <xliff:g id="COUNT">%d</xliff:g> секунде(и)"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Пре једног минута"</item>
-    <item quantity="other" msgid="2176942008915455116">"пре <xliff:g id="COUNT">%d</xliff:g> минута"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Пре сат времена"</item>
-    <item quantity="other" msgid="2467273239587587569">"пре <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"У последња(их) <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Прошлог месеца"</string>
     <string name="older" msgid="5211975022815554840">"Старије"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"јуче"</item>
-    <item quantity="other" msgid="2479586466153314633">"пре <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"за 1 секунду"</item>
-    <item quantity="other" msgid="1241926116443974687">"за <xliff:g id="COUNT">%d</xliff:g> секунде(и)"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"за 1 минут"</item>
-    <item quantity="other" msgid="3330713936399448749">"за <xliff:g id="COUNT">%d</xliff:g> минута"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"за 1 сат"</item>
-    <item quantity="other" msgid="547290677353727389">"за <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"сутра"</item>
-    <item quantity="other" msgid="5109449375100953247">"за <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Пре једне сек"</item>
-    <item quantity="other" msgid="3699169366650930415">"пре <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Пре један мин"</item>
-    <item quantity="other" msgid="851164968597150710">"пре <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Пре сат времена"</item>
-    <item quantity="other" msgid="6889970745748538901">"пре <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"јуче"</item>
-    <item quantity="other" msgid="3453342639616481191">"пре <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"за 1 сек"</item>
-    <item quantity="other" msgid="5495880108825805108">"за <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"за 1 мин"</item>
-    <item quantity="other" msgid="4216113292706568726">"за <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"за 1 сат"</item>
-    <item quantity="other" msgid="3705373766798013406">"за <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"сутра"</item>
-    <item quantity="other" msgid="2973062968038355991">"за <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"дана <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"у <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"у <xliff:g id="YEAR">%s</xliff:g>."</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android се покреће…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Меморија се оптимизује."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимизовање апликације <xliff:g id="NUMBER_0">%1$d</xliff:g> од <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Припрема се <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Покретање апликација."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Завршавање покретања."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s жели да се повеже са мрежом %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликација %1$s жели да се повеже на Wi-Fi мрежу %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Покрените Wi-Fi Direct. Тиме ћете искључити клијента/хотспот за Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS захтев је промењен у DIAL захтев."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS захтев је промењен у USSD захтев."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS захтев је промењен у нови SS захтев."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB порт за периферијске уређаје"</string>
 </resources>
diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml
index 29b120c..35a84eb 100755
--- a/core/res/res/values-sv/donottranslate-cldr.xml
+++ b/core/res/res/values-sv/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ad5c495..f31ba4d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Inställningar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vill aktivera Explore by Touch. När funktionen är aktiv kan du höra eller se beskrivningar av vad du har under fingret eller utföra gester för att göra saker med telefonen."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"för 1 månad sedan"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"För mer än en månad sedan"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"för 1 sekund sedan"</item>
-    <item quantity="other" msgid="3903706804349556379">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"för 1 minut sedan"</item>
-    <item quantity="other" msgid="2176942008915455116">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"för 1 timme sedan"</item>
-    <item quantity="other" msgid="2467273239587587569">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"De senaste <xliff:g id="COUNT">%d</xliff:g> dagarna"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Föregående månad"</string>
     <string name="older" msgid="5211975022815554840">"Äldre"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"igår"</item>
-    <item quantity="other" msgid="2479586466153314633">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
-    <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"om 1 timme"</item>
-    <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"imorgon"</item>
-    <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"för 1 sek sedan"</item>
-    <item quantity="other" msgid="3699169366650930415">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"för 1 minut sedan"</item>
-    <item quantity="other" msgid="851164968597150710">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"för 1 timme sedan"</item>
-    <item quantity="other" msgid="6889970745748538901">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"igår"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"om 1 sekund"</item>
-    <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"om 1 minut"</item>
-    <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"om 1 timme"</item>
-    <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"imorgon"</item>
-    <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"den <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android startar …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Lagringsutrymmet optimeras."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimerar app <xliff:g id="NUMBER_0">%1$d</xliff:g> av <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> förbereds."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Appar startas."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Uppgraderingen är klar."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s vill ansluta till %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vill ansluta till Wi-Fi-nätverket %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Starta direkt Wi-Fi-användning. Detta inaktiverar Wi-Fi-användning med klient/trådlös surfzon."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-begäran har ändrats till en DIAL-begäran."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-begäran har ändrats till en USSD-begäran."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-begäran har ändrats till en ny SS-begäran."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Perifer USB-port"</string>
 </resources>
diff --git a/core/res/res/values-sw/donottranslate-cldr.xml b/core/res/res/values-sw/donottranslate-cldr.xml
index b6304e7..7313c71 100755
--- a/core/res/res/values-sw/donottranslate-cldr.xml
+++ b/core/res/res/values-sw/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%Y %B %-e</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y %b %-e</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2db8cd6..5e57cc1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hali ya ndege IMEWASHWA"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hali ya ndege IMEZIMWA"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Mipangilio"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Usaidizi wa Sauti"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Funga sasa"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> inataka kuwezesha Kuchunguza kwa Kugusa. Wakati Kuchunguza kwa Kugusa kumewezeshwa, unaweza kusikia au kuona maelezo ya kilicho chini ya kidole chako au kutumia ishara ili kuingiliana na simu."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Mwezi 1 uliopita"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Kabla ya mwezi 1 uliopita"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Sekunde 1 iliopita"</item>
-    <item quantity="other" msgid="3903706804349556379">"sekunde <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Dakika 1 iliyopita"</item>
-    <item quantity="other" msgid="2176942008915455116">"Dakika <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Saa 1 iliyopita"</item>
-    <item quantity="other" msgid="2467273239587587569">"Saa <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Mwezi uliopita"</string>
     <string name="older" msgid="5211975022815554840">"Kuukuu zaidi"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"jana"</item>
-    <item quantity="other" msgid="2479586466153314633">"siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"kati ya sekunde 1"</item>
-    <item quantity="other" msgid="1241926116443974687">"kati ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"kati ya dakika  1"</item>
-    <item quantity="other" msgid="3330713936399448749">"baada ya dakika <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"kati ya saa 1"</item>
-    <item quantity="other" msgid="547290677353727389">"kati ya saa <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"kesho"</item>
-    <item quantity="other" msgid="5109449375100953247">"katika siku <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Sekunde 1 iliyopita"</item>
-    <item quantity="other" msgid="3699169366650930415">"Sekunde <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Dakika 1 iliyopita"</item>
-    <item quantity="other" msgid="851164968597150710">"Dakika <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Saa 1 iliyopita"</item>
-    <item quantity="other" msgid="6889970745748538901">"Saa <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"jana"</item>
-    <item quantity="other" msgid="3453342639616481191">"siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"kati ya sekunde 1"</item>
-    <item quantity="other" msgid="5495880108825805108">"kati ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"baada ya dakika 1"</item>
-    <item quantity="other" msgid="4216113292706568726">"kati ya dakika<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"kati ya saa 1"</item>
-    <item quantity="other" msgid="3705373766798013406">"katika saa <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"kesho"</item>
-    <item quantity="other" msgid="2973062968038355991">"kati ya siku <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"tarehe <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"Saa <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ndani  ya <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Inaanzisha Android..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Inaboresha hifadhi."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Inaboresha programu <xliff:g id="NUMBER_0">%1$d</xliff:g> kutoka <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Inaandaa <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Programu zinaanza"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Inamaliza kuwasha."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> inaendelea"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s angependa kuunganisha kwenye %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programu ya %1$s ingependa kuunganisha kwenye Mtandao wa Wifi wa %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Programu"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Mtandao hewa Moja kwa moja"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Anzisha Wi-Fi Moja kwa Moja. Hii itazima mteja/mtandao-hewa wa Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Ombi la SS limerekebishwa na kuwa ombi la DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Ombi la SS limerekebishwa na kuwa ombi la USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Ombi la SS limerekebishwa na kuwa ombi jipya la SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Mlango wa USB wa Pembeni"</string>
 </resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 570671b..14a0e67 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"விமானப் பயன்முறை இயக்கத்தில் உள்ளது"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"விமானப் பயன்முறை முடக்கத்தில் உள்ளது"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"அமைப்பு"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"குரல் உதவி"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"இப்போது பூட்டு"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"தொடுவதன் மூலம் அறிக என்பதை இயக்க <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> விரும்புகிறது. தொடுவதன் மூலம் அறிக என்பது இயக்கப்பட்டிருக்கும்போது, உங்கள் விரலுக்கு அடியில் இருப்பவையின் விளக்கங்களை நீங்கள் கேட்கவோ, பார்க்கவோ செய்யலாம் அல்லது மொபைலுடன் ஊடாட சைகைகளை மேற்கொள்ளலாம்."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 மாதத்திற்கு முன்பு"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 மாதத்திற்கு முன்பு"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 வினாடிக்கு முன்பு"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 நிமிடம் முன்பு"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> நிமிடத்திற்கு முன்"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 மணிநேரம் முன்பு"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்திற்கு முன்பு"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"கடந்த <xliff:g id="COUNT">%d</xliff:g> நாட்கள்"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"சென்ற மாதம்"</string>
     <string name="older" msgid="5211975022815554840">"பழையது"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"நேற்று"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> நாட்களுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 வினாடியில்"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளில்"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 நிமிடத்தில்"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்களில்"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 மணிநேரத்தில்"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்தில்"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"நாளை"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> நாட்களில்"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 வினாடி முன்பு"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 நிமிடம் முன்பு"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> நிமிடத்திற்கு முன்"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 மணிநேரம் முன்பு"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்திற்கு முன்பு"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"நேற்று"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> நாட்களுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 வினாடியில்"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளில்"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 நிமிடத்தில்"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்களில்"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 மணிநேரத்தில்"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்தில்"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"நாளை"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> நாட்களில்"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> அன்று"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> இல்"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> இல்"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android துவங்குகிறது..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"சேமிப்பகத்தை உகந்ததாக்குகிறது."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g> பயன்பாட்டை ஒருங்கிணைக்கிறது."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ஐத் தயார்செய்கிறது."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"பயன்பாடுகள் தொடங்கப்படுகின்றன."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"துவக்குதலை முடிக்கிறது."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> இயங்குகிறது"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" இணைய இணைப்பு மோசமாக உள்ளது."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s , %2$s உடன் இணைக்க விரும்புகிறது"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s வைஃபை நெட்வொர்க்குடன், %1$s பயன்பாடு இணைக்க விரும்புகிறது"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ஒரு பயன்பாடு"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"வைஃபை Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"வைஃபை Direct ஐத் தொடங்குக. இது வைஃபை க்ளையண்ட்/ஹாட்ஸ்பாட்டை முடக்கும்."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS கோரிக்கையானது DIAL கோரிக்கைக்கு மாற்றப்பட்டது."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS கோரிக்கையானது USSD கோரிக்கைக்கு மாற்றப்பட்டது."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS கோரிக்கையானது புதிய SS கோரிக்கைக்கு மாற்றப்பட்டது."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB பெரிபெரல் போர்ட்"</string>
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 9975c71..72df68b 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ఎయిర్‌ప్లేన్ మోడ్ ఆన్‌లో ఉంది"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ఎయిర్‌ప్లేన్ మోడ్ ఆఫ్‌లో ఉంది"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"సెట్టింగ్‌లు"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"వాయిస్ సహాయకం"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ఇప్పుడు లాక్ చేయండి"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణ ఆన్ చేయబడినప్పుడు, మీరు మీ వేలి క్రింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా ఫోన్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 నెల క్రితం"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 నెలకు ముందు"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 సెకను క్రితం"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> సెకన్ల క్రితం"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 నిమిషం క్రితం"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల క్రితం"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 గంట క్రితం"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> గంటల క్రితం"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"గత <xliff:g id="COUNT">%d</xliff:g> రోజులు"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"గత నెల"</string>
     <string name="older" msgid="5211975022815554840">"పాతది"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"నిన్న"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> రోజుల క్రితం"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 సెకనులో"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 నిమిషంలో"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల్లో"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 గంటలో"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> గంటల్లో"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"రేపు"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> రోజుల్లో"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 సెక క్రితం"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> సెక క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 నిమి క్రితం"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> నిమి క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 గంట క్రితం"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> గంటల క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"నిన్న"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> రోజుల క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 సెకనులో"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 నిమిషంలో"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల్లో"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 గంటలో"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> గంటల్లో"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"రేపు"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> రోజుల్లో"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>న"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>కి"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>లో"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ప్రారంభమవుతోంది…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"నిల్వను అనుకూలపరుస్తోంది."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>లో <xliff:g id="NUMBER_0">%1$d</xliff:g> అనువర్తనాన్ని అనుకూలీకరిస్తోంది."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ని సిద్ధం చేస్తోంది."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"అనువర్తనాలను ప్రారంభిస్తోంది."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"బూట్‌ను ముగిస్తోంది."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> అమలవుతోంది"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" బలహీన ఇంటర్నెట్ కనెక్షన్‌ను కలిగి ఉంది."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్‌ని అనుమతించాలా?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s %2$sకి కనెక్ట్ చేయాలనుకుంటున్నారు"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s అనువర్తనం %2$s Wifi నెట్‌వర్క్‌కు కనెక్ట్ చేయాలనుకుంటోంది"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ఒక అనువర్తనం"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directను ప్రారంభించండి. దీని వలన Wi-Fi క్లయింట్/హాట్‌స్పాట్ ఆపివేయబడుతుంది."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS అభ్యర్థన డయల్ అభ్యర్థనగా సవరించబడింది."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS అభ్యర్థన USSD అభ్యర్థనగా సవరించబడింది."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS అభ్యర్థన కొత్త SS అభ్యర్థనగా సవరించబడింది."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB పెరిఫెరాల్ పోర్ట్"</string>
 </resources>
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
index 2f389f7..867a58e 100755
--- a/core/res/res/values-th-rTH/donottranslate-cldr.xml
+++ b/core/res/res/values-th-rTH/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
diff --git a/core/res/res/values-th/donottranslate-cldr.xml b/core/res/res/values-th/donottranslate-cldr.xml
index 2f389f7..867a58e 100755
--- a/core/res/res/values-th/donottranslate-cldr.xml
+++ b/core/res/res/values-th/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index f9bcd79..eaf0827 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"เปิดโหมดใช้งานบนเครื่องบิน"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"โหมดใช้งานบนเครื่องบินปิดทำงานอยู่"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"การตั้งค่า"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ตัวช่วยเสียง"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ล็อกเลย"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ต้องการเปิดใช้งาน \"สำรวจโดยการแตะ\" เมื่อเปิดใช้งานแล้ว คุณสามารถฟังหรือดูคำอธิบายของสิ่งที่อยู่ใต้นิ้วข​​องคุณ หรือใช้ท่าทางสัมผัสต่างๆ เพื่อโต้ตอบกับโทรศัพท์ได้"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 เดือนที่ผ่านมา"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ก่อน 1 เดือนที่แล้ว"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 วินาทีที่แล้ว"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> วินาทีที่แล้ว"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 นาทีที่ผ่านมา"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> นาทีที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ชั่วโมงที่ผ่านมา"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมงที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> วันที่แล้ว"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"เดือนที่แล้ว"</string>
     <string name="older" msgid="5211975022815554840">"เก่ากว่า"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"เมื่อวาน"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> วันที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ใน 1 วินาที"</item>
-    <item quantity="other" msgid="1241926116443974687">"ใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ใน 1 นาที"</item>
-    <item quantity="other" msgid="3330713936399448749">"ใน <xliff:g id="COUNT">%d</xliff:g> นาที"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ใน 1 ชั่วโมง"</item>
-    <item quantity="other" msgid="547290677353727389">"ใน <xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"พรุ่งนี้"</item>
-    <item quantity="other" msgid="5109449375100953247">"ใน <xliff:g id="COUNT">%d</xliff:g> วัน"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 วินาทีที่แล้ว"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> วินาทีที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 นาทีที่ผ่านมา"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> นาทีที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ชั่วโมงที่ผ่านมา"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมงที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"เมื่อวาน"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> วันที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ใน 1 วินาที"</item>
-    <item quantity="other" msgid="5495880108825805108">"ใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ใน 1 นาที"</item>
-    <item quantity="other" msgid="4216113292706568726">"ใน <xliff:g id="COUNT">%d</xliff:g> นาที"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ใน 1 ชั่วโมง"</item>
-    <item quantity="other" msgid="3705373766798013406">"ใน <xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"พรุ่งนี้"</item>
-    <item quantity="other" msgid="2973062968038355991">"ใน <xliff:g id="COUNT">%d</xliff:g> วัน"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"ในวันที่ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ที่ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ใน <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android กำลังเริ่มต้น…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"กำลังเพิ่มประสิทธิภาพพื้นที่จัดเก็บข้อมูล"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"กำลังเพิ่มประสิทธิภาพแอปพลิเคชัน <xliff:g id="NUMBER_0">%1$d</xliff:g> จาก <xliff:g id="NUMBER_1">%2$d</xliff:g> รายการ"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"กำลังเตรียม <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"กำลังเริ่มต้นแอปพลิเคชัน"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"เสร็จสิ้นการบูต"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงาน"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s ต้องการเชื่อมต่อ %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"แอปพลิเคชัน %1$s ต้องการเชื่อมต่อเครือข่าย Wi-Fi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"แอปพลิเคชัน"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"เริ่มการทำงาน WiFi Direct ซึ่งจะเป็นการปิดการทำงาน WiFi ไคลเอ็นต์/ฮอตสปอต"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ DIAL"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ SS ใหม่"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"อุปกรณ์สำหรับต่อพอร์ต USB"</string>
 </resources>
diff --git a/core/res/res/values-tl/donottranslate-cldr.xml b/core/res/res/values-tl/donottranslate-cldr.xml
index 4f69833..7313c71 100755
--- a/core/res/res/values-tl/donottranslate-cldr.xml
+++ b/core/res/res/values-tl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y %B %-e</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y %b %-e</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 2364e29..707402d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Naka-ON ang airplane mode"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Naka-OFF ang airplane mode"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Mga Setting"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"I-lock ngayon"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Nais paganahin ng <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ang Galugarin sa pamamagitan ng pagpindot. Kapag naka-on ang Galugarin sa pamamagitan ng pagpindot, maaari mong marinig o makita ang mga paglalarawan ng nasa ilalim ng iyong daliri o maaari kang magsagawa ng mga galaw upang makipag-ugnayan sa telepono."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 buwan ang nakalipas"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Bago ang nakalipas na 1 buwan"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 segundo ang nakakalipas"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo ang nakalipas"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuto ang nakalipas"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto ang nakalipas"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 oras ang nakalipas"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> (na) oras ang nakalipas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Huling <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Nakaraang buwan"</string>
     <string name="older" msgid="5211975022815554840">"Mas luma"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"kahapon"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> (na) araw ang nakalipas"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"sa 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"sa <xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"sa 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"sa <xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"sa 1 oras"</item>
-    <item quantity="other" msgid="547290677353727389">"sa <xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"bukas"</item>
-    <item quantity="other" msgid="5109449375100953247">"sa <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 segundo ang nakalipas"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minuto ang nakalipas"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 oras ang nakalipas"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> (na) oras ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"kahapon"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> (na) araw ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"sa 1 seg"</item>
-    <item quantity="other" msgid="5495880108825805108">"sa <xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"sa 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"sa <xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"sa 1 oras"</item>
-    <item quantity="other" msgid="3705373766798013406">"sa <xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"bukas"</item>
-    <item quantity="other" msgid="2973062968038355991">"sa <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"sa <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"nang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"sa <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Nagsisimula ang Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Ino-optimize ang storage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ino-optimize ang app <xliff:g id="NUMBER_0">%1$d</xliff:g> ng <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Ihinahanda ang <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Sinisimulan ang apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Pagtatapos ng pag-boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"gustong kumonekta ni %1$s sa %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Gustong kumonekta ng application na %1$s sa Wifi Network na %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Isang application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Simulan ang Wi-Fi Direct. I-o-off nito ang client/hotspot ng Wi-Fi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Ginawang DIAL request ang SS request."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Ginawang USSD request ang SS request."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Ginawang bagong SS request ang SS request."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml
index 8bdcf48..0577fab 100755
--- a/core/res/res/values-tr/donottranslate-cldr.xml
+++ b/core/res/res/values-tr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s %s %s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d %b %Y %H:%M:%S</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 07d1ba7..36f6f8f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -55,7 +55,7 @@
     <string name="mmiComplete" msgid="8232527495411698359">"MMI tamamlandı."</string>
     <string name="badPin" msgid="9015277645546710014">"Yazdığınız eski PIN doğru değil."</string>
     <string name="badPuk" msgid="5487257647081132201">"Yazdığınız PUK doğru değil."</string>
-    <string name="mismatchPin" msgid="609379054496863419">"Girdiğiniz PIN kodları eşleşmiyor"</string>
+    <string name="mismatchPin" msgid="609379054496863419">"Girdiğiniz PIN\'ler eşleşmiyor"</string>
     <string name="invalidPin" msgid="3850018445187475377">"4 ila 8 rakamdan oluşan bir PIN girin."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"8 veya daha uzun basamaklı bir PUK kodu yazın."</string>
     <string name="needPuk" msgid="919668385956251611">"SIM kartınızın PUK kilidi devrede. Kilidi açmak için PUK kodunu yazın."</string>
@@ -192,7 +192,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere mevcut cihazınızın durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Sessiz mod"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ses KAPALI"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ses AÇIK"</string>
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ses Yardımı"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
@@ -208,8 +209,8 @@
     <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Size maliyet getirebilecek işlemler yapma."</string>
-    <string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
-    <string name="permgroupdesc_messages" msgid="7821999071003699236">"SMS mesajlarınızı, e-posta iletilerinizi ve diğer mesajlarınızı okuyup yazma."</string>
+    <string name="permgrouplab_messages" msgid="7521249148445456662">"İletileriniz"</string>
+    <string name="permgroupdesc_messages" msgid="7821999071003699236">"SMS, e-posta ve diğer iletilerinizi okuyup yazma."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Kişisel bilgileriniz"</string>
     <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"Sizinle ilgili, kişi kartınızda kayıtlı bilgilere doğrudan erişim."</string>
     <string name="permgrouplab_socialInfo" msgid="5799096623412043791">"Sosyal bilgileriniz"</string>
@@ -269,13 +270,13 @@
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"SD karta erişin."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Erişilebilirlik özellikleri"</string>
     <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Engelli kullanıcılara yardımcı olan teknolojinin istekte bulunabileceği özellikler."</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pencere içeriğini alın"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Etkileşim kurduğunuz pencerenin içeriğini inceleyin."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Dokunarak Keşfet\'i açın"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pencere içeriğini alma"</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Etkileşim kurduğunuz pencerenin içeriğini inceler."</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Dokunarak Keşfet\'i açma"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Dokunulan öğeler sesli olarak okunur ve ekranı keşfetmek için hareketler kullanılabilir."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Gelişmiş web erişilebilirliğini açın"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Gelişmiş web erişilebilirliğini açma"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Uygulamanın erişilebilirliğini artırmak için komut dosyaları yüklenebilir."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Yazdığınız metni izleyin"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Yazdığınız metni izleme"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kredi kartı ve şifre gibi kişisel bilgiler içerir."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string>
@@ -290,25 +291,25 @@
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"giden çağrıları yeniden yönlendir"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Uygulamaya, giden bir çağrının numarası çevrilirken çağrıyı farklı bir numaraya yönlendirme ya da tamamen kapatma seçeneğiyle birlikte numarayı görme izni verir."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"kısa mesajları al (SMS)"</string>
-    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Uygulamaya SMS mesajlarını alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen mesajları takip edip size göstermeden silebileceği anlamına gelir."</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Uygulamaya SMS iletilerini alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen iletileri takip edip size göstermeden silebileceği anlamına gelir."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"kısa mesajları (MMS) al"</string>
-    <string name="permdesc_receiveMms" msgid="533019437263212260">"Uygulamaya MMS mesajlarını alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen mesajları takip edip size göstermeden silebileceği anlamına gelir."</string>
+    <string name="permdesc_receiveMms" msgid="533019437263212260">"Uygulamaya MMS iletilerini alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen iletileri takip edip size göstermeden silebileceği anlamına gelir."</string>
     <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"acil durum yayınlarını al"</string>
     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Uygulamaya, acil yayın mesajları alma ve işleme izni verir. Bu izin, sadece sistem uygulamaları için kullanılabilir."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"hücre yayını mesajlarını oku"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Uygulamaya, cihazınız tarafından alınan hücre yayını mesajlarını okuma izni verir. Hücre yayını uyarıları bazı yerlerde acil durumlar konusunda sizi uyarmak için gönderilir. Kötü amaçlı uygulamalar acil hücre yayını alındığında cihazınızın performansına ya da çalışmasına engel olabilir."</string>
-    <string name="permlab_sendSms" msgid="5600830612147671529">"SMS mesajları gönder"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"Uygulamaya SMS mesajları gönderme izni verir. Bu durum beklenmeyen ödemelere neden olabilir. Kötü amaçlı uygulamalar onayınız olmadan mesajlar göndererek sizi zarara uğratabilir."</string>
+    <string name="permlab_sendSms" msgid="5600830612147671529">"SMS iletileri gönder"</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"Uygulamaya SMS iletisi gönderme izni verir. Bu durum beklenmeyen ödemelere neden olabilir. Kötü amaçlı uygulamalar onayınız olmadan iletiler göndererek sizi zarara uğratabilir."</string>
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"mesajla yanıtla etkinlikleri gönder"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"Uygulamaya, gelen çağrıları mesajla yanıtlama etkinliklerini işlemek üzere diğer mesajlaşma uygulamalarına istek gönderme izni verir."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"kısa mesajlarımı (SMS veya MMS) oku"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Uygulamaya tabletinizde veya SIM kartta saklanan SMS mesajlarını okuma izni verir. Bu izin, uygulamanın tüm SMS mesajlarını içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Uygulamaya, TV\'nizde veya SIM kartta depolanmış SMS mesajlarını okuma izni verir. Bu izin, uygulamanın içeriğe veya gizliliğe bakılmaksızın tüm SMS mesajlarını okumasına olanak sağlar."</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Uygulamaya telefonunuzda veya SIM kartta saklanan SMS mesajlarını okuma izni verir. Bu izin, uygulamanın tüm SMS mesajlarını içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Uygulamaya tabletinizde veya SIM kartta saklanan SMS iletilerini okuma izni verir. Bu izin, uygulamanın tüm SMS iletilerini içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Uygulamaya, TV\'nizde veya SIM kartta depolanmış SMS iletilerini okuma izni verir. Bu izin, uygulamanın içeriğe veya gizliliğe bakılmaksızın tüm SMS iletilerini okumasına olanak sağlar."</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Uygulamaya telefonunuzda veya SIM kartta saklanan SMS iletilerini okuma izni verir. Bu izin, uygulamanın tüm SMS iletilerini içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
     <string name="permlab_writeSms" msgid="3216950472636214774">"kısa mesajlarımı (SMS veya MMS) düzenle"</string>
-    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Uygulamaya, tabletinizde veya SIM kartınızda depolanan SMS mesajlarına yazma izni verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
-    <string name="permdesc_writeSms" product="tv" msgid="955871498983538187">"Uygulamaya, TV\'niz ya da SIM kartınızda saklanan SMS mesajlarına yazma izni verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
-    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Uygulamaya, telefonunuzdaki veya SIM kartınızdaki SMS mesajlarına yazma izni verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
+    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Uygulamaya, tabletinizde veya SIM kartınızda depolanan SMS iletilerine yazma izni verir. Kötü amaçlı uygulamalar iletilerinizi silebilir."</string>
+    <string name="permdesc_writeSms" product="tv" msgid="955871498983538187">"Uygulamaya, TV\'niz ya da SIM kartınızda saklanan SMS iletilerine yazma izni verir. Kötü amaçlı uygulamalar iletilerinizi silebilir."</string>
+    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Uygulamaya, telefonunuzdaki veya SIM kartınızdaki SMS iletilerine yazma izni verir. Kötü amaçlı uygulamalar iletilerinizi silebilir."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"kısa mesajları (WAP) al"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Uygulamaya WAP mesajlarını alma ve işleme izni verir. Buna, size gönderilen mesajları takip edip size göstermeden silebilme izni de dahildir."</string>
     <string name="permlab_receiveBluetoothMap" msgid="7593811487142360528">"Bluetooth iletilerini al (MAP)"</string>
@@ -370,7 +371,7 @@
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"paket ile kaldırılan yayını gönder"</string>
     <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Uygulamaya, bir uygulama paketinin kaldırıldığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar çalışan diğer uygulamaları kapatmak için bunu kullanabilir."</string>
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS ile alınan yayın gönder"</string>
-    <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Uygulamaya, SMS mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte SMS mesajları göndermek için bunu kullanabilir."</string>
+    <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Uygulamaya, SMS iletisi alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte SMS iletileri göndermek için bunu kullanabilir."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH ile alınan yayın gönder"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Uygulamaya, WAP PUSH mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte MMS bildirimleri oluşturmak veya bir web sayfasının içeriğini sessiz şekilde zararlı öğelerle değiştirmek için bunu kullanabilir."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
@@ -526,15 +527,15 @@
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"sosyal akışınızı okuma"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Uygulamaya size veya arkadaşlarınıza ait sosyal güncellemelere erişme ve bunları senkronize etme izni verir. Bilgi paylaşırken dikkatli olun. Bu izin, uygulamanın sosyal ağlarda sizinle arkadaşlarınız arasındaki iletişimi, gizliliğine bakılmaksızın okumasına olanak sağlar. Not: Bu izin tüm sosyal ağlar için geçerli olmayabilir."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"sosyal akışınıza yazma"</string>
-    <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Uygulamaya arkadaşlarınızın sosyal güncellemelerini gösterme izni verir. Bilgi paylaşırken dikkatli olun -- Bu uygulama bir arkadaşınızdan geliyormuş gibi görünen mesajlar oluşturabilir. Not: Bu izin, tüm sosyal ağlarda geçerli olmayabilir."</string>
+    <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Uygulamaya arkadaşlarınızın sosyal güncellemelerini gösterme izni verir. Bilgi paylaşırken dikkatli olun -- Bu uygulama bir arkadaşınızdan geliyormuş gibi görünen iletiler oluşturabilir. Not: Bu izin, tüm sosyal ağlarda geçerli olmayabilir."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"takvim etkinliklerini ve gizli bilgileri oku"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Uygulamaya, arkadaşlarınızın ve iş arkadaşlarınızın etkinlikleri de olmak üzere tabletinizde depolanan tüm takvim etkinliklerini okuma izni verir. Bu izin, uygulamanın takvim verilerinizi gizliliğine ve hassaslığına bakmaksızın paylaşmasına ve kaydetmesine olanak sağlayabilir."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Uygulamaya, arkadaşlarınızın ve iş arkadaşlarınızın etkinlikleri dahil olmak üzere TV\'nizde kayıtlı tüm takvim etkinliklerini okuma izni verir. Bu da uygulamanın gizlilik ve duyarlılık dikkate alınmaksızın takvim verilerinizi paylaşmasına veya kaydetmesine olanak sağlayabilir."</string>
     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Uygulamaya, arkadaşlarınızın ve iş arkadaşlarınızın etkinlikleri de dahil olmak üzere telefonunuzda depolanan tüm takvim etkinliklerini okuma izni verir. Bu izin, uygulamanın takvim verilerinizi gizliliğine ve hassaslığına bakmaksızın paylaşmasına ve kaydetmesine olanak sağlayabilir."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"sahibin bilgisi olmadan takvim etkinlikleri ekle veya mevcut etkinlikleri değiştir ve misafirlere e-posta gönder"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere tabletinizde değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen mesajlar göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere tabletinizde değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen iletiler göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere cihazınızda değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın, takvim sahiplerinden gelmiş gibi görünen iletiler göndermesine veya takvim sahiplerinin bilgisi olmadan etkinlikleri değiştirmesine olanak sağlayabilir."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere telefonunuzda değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen mesajlar göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere telefonunuzda değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen iletiler göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"test için sahte konum kaynakları"</string>
     <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Test amacıyla veya yeni bir konum sağlayıcı yüklemek için sahte konum kaynakları oluşturma. Bu izin, uygulamanın GPS veya konum sağlayıcıları gibi diğer konum kaynakları tarafından döndürülen konum ve/veya durum bilgisini geçersiz kılmasına olanak sağlar."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ek konum sağlayıcı komutlarına eriş"</string>
@@ -747,9 +748,9 @@
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Uygulamaya, o anda senkronize olan özet akışları ile ilgili bilgi alma izni verir."</string>
     <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abone olunan yayınları yazma"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Uygulamaya, o anda senkronize edilmiş özet akışlarını değiştirme izni verir. Kötü amaçlı uygulamalar senkronize edilmiş özet akışlarını değiştirebilir."</string>
-    <string name="permlab_readDictionary" msgid="4107101525746035718">"sözlüğe eklediğim terimleri oku"</string>
+    <string name="permlab_readDictionary" msgid="4107101525746035718">"sözlüğe eklediğiniz terimleri okuma"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Uygulamaya, kullanıcının kullanıcı sözlüğünde depolamış olabileceği kelimeleri, adları ve kelime öbeklerini okuma izni verir."</string>
-    <string name="permlab_writeDictionary" msgid="2183110402314441106">"kullanıcı tanımlı sözlüğe kelime ekle"</string>
+    <string name="permlab_writeDictionary" msgid="2183110402314441106">"kullanıcı tanımlı sözlüğe kelime ekleme"</string>
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Uygulamaya, kullanıcı sözlüğüne yeni kelimeler yazma izni verir."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"USB belleğini okuma"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"SD kartımın içeriğini oku"</string>
@@ -817,11 +818,11 @@
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Ekran kilidini açarken yapılan yanlış şifre girme denemelerini izle ve çok fazla sayıda yanlış şifre girme denemesi yapılmışsa tableti kilitle veya tabletteki tüm verileri sil."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Ekran kilidi açılırken girilen hatalı şifre sayısını takip etme ve çok fazla sayıda hatalı şifre girildiğinde TV\'yi kilitleme veya TV\'nin tüm verilerini silme."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Ekran kilidini açarken yapılan yanlış şifre girişi denemelerini izle ve çok sayıda yanlış şifre girişi denemesi yapılmışsa telefonu kilitle veya telefonun tüm verilerini sil."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekran kilidini açma şifresini değiştir"</string>
+    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekran kilidini açma şifresini değiştirme"</string>
     <string name="policydesc_resetPassword" msgid="605963962301904458">"Ekran kilidini açma şifresini değiştirme."</string>
-    <string name="policylab_forceLock" msgid="2274085384704248431">"Ekranı kilitle"</string>
+    <string name="policylab_forceLock" msgid="2274085384704248431">"Ekranı kilitleme"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Ekranın nasıl ve ne zaman kilitlendiğini denetleme."</string>
-    <string name="policylab_wipeData" msgid="3910545446758639713">"Tüm verileri sil"</string>
+    <string name="policylab_wipeData" msgid="3910545446758639713">"Tüm verileri silme"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek tabletteki verileri uyarıda bulunmadan silme."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Fabrika ayarlarına sıfırlama yoluyla TV\'nin verilerini uyarı vermeksizin silme."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek telefondaki verileri uyarıda bulunmadan silme."</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>, Dokunarak Keşfet özelliğini etkinleştirmek istiyor. Dokunarak Keşfet açık olduğunda parmağınızın altındaki öğelere ait açıklamaları duyabilir veya görebilir ya da telefonla etkileşimde bulunmak için birtakım hareketler yapabilirsiniz."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay önce"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay önce"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 saniye önce"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 dakika önce"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 saat önce"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Son <xliff:g id="COUNT">%d</xliff:g> gün"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Son ay"</string>
     <string name="older" msgid="5211975022815554840">"Daha eski"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"dün"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 saniye içinde"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 dakika içinde"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 saat içinde"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"yarın"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 saniye önce"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 dak. önce"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 saat önce"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"dün"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 san. içinde"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 dak. içinde"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 saat içinde"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"yarın"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> tarihinde"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> yılında"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android başlatılıyor…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Depolama optimize ediliyor."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g> uygulama optimize ediliyor."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> hazırlanıyor."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Uygulamalar başlatılıyor"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Açılış tamamlanıyor."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string>
@@ -1348,12 +1284,12 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s, %2$s ile bağlantı kurmak istiyor"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s uygulaması %2$s Kablosuz Ağına bağlanmak istiyor"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Bir uygulama"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantıyı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan bağlantı başlatılamadı."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantı\'yı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan Bağlantı başlatılamadı."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan Bağlantı özelliği açık"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string>
     <string name="accept" msgid="1645267259272829559">"Kabul et"</string>
     <string name="decline" msgid="2112225451706137894">"Reddet"</string>
@@ -1367,11 +1303,11 @@
     <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile bağlantıya sahipken TV\'nizin Kablosuz bağlantısı geçici olarak kesilecek."</string>
     <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
-    <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
-    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çok sayıda SMS mesajı gönderiyor. Bu uygulamanın mesaj göndermeye devam etmesine izin veriyor musunuz?"</string>
+    <string name="sms_control_title" msgid="7296612781128917719">"SMS iletileri gönderiliyor"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çok sayıda SMS iletisi gönderiyor. Bu uygulamanın ileti göndermeye devam etmesine izin veriyor musunuz?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"İzin ver"</string>
     <string name="sms_control_no" msgid="625438561395534982">"Reddet"</string>
-    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;, &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; adresine bir mesaj göndermek istiyor."</string>
+    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;, &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; adresine bir ileti göndermek istiyor."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Bu işlem, mobil hesabınızdan "<b>"ödeme alınmasına neden olabilir"</b>"."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bu işlem, mobil hesabınızdan ödeme alınmasına neden olacak."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Gönder"</string>
@@ -1524,7 +1460,7 @@
     <string name="submit" msgid="1602335572089911941">"Gönder"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Araba modu etkin"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Araba modundan çıkmak için dokunun."</string>
-    <string name="tethered_notification_title" msgid="3146694234398202601">"Doğrudan bağlantı veya ortak erişim noktası etkin"</string>
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering veya hotspot etkin"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"Kurulum için dokunun."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Geri"</string>
     <string name="next_button_label" msgid="1080555104677992408">"İleri"</string>
@@ -1847,8 +1783,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Sabitlemeyi kaldırmadan önce şifre sor"</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>
-    <string name="downtime_condition_summary" msgid="8761776337475705749">"Kesinti süreniz <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatinde sona erene kadar"</string>
-    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kullanım dışı kalma durumunuz bitene kadar"</string>
+    <string name="downtime_condition_summary" msgid="8761776337475705749">"Bildirim istenmeyen zaman <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatinde sona erene kadar"</string>
+    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Bildirim istenmeyen zaman bitene kadar"</string>
   <plurals name="zen_mode_duration_minutes_summary">
     <item quantity="one" msgid="3177683545388923234">"Bir dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
     <item quantity="other" msgid="2787867221129368935">"%1$d dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS isteği DIAL isteği olarak değiştirildi."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS isteği USSD isteği olarak değiştirildi."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS isteği yeni SS isteği olarak değiştirildi."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Çevre Birimi Bağlantı Noktası"</string>
 </resources>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index c137df9..75025d8 100755
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y р.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y р., %H:%M:%S</string>
diff --git a/core/res/res/values-uk/donottranslate-cldr.xml b/core/res/res/values-uk/donottranslate-cldr.xml
index b8c0d1e..1c25b4d 100755
--- a/core/res/res/values-uk/donottranslate-cldr.xml
+++ b/core/res/res/values-uk/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y р.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 79281b3..1768942 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -71,7 +71,7 @@
     <string name="ClirMmi" msgid="7784673673446833091">"Вихід. ід. абонента"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"Ідентифікатор під’єднаної лінії"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"Обмеження ідентифікатора під’єднаної лінії"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"Переадрес. виклику"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"Переадресація виклику"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Паралел. виклик"</string>
     <string name="BaMmi" msgid="455193067926770581">"Заборона викл."</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Зміна пароля"</string>
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим польоту ВВІМК."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим польоту ВИМК."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Налаштування"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Голос. підказки"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Блокувати зараз"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
@@ -879,9 +880,9 @@
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
     <string name="phoneTypeCustom" msgid="1644738059053355820">"Указати"</string>
-    <string name="phoneTypeHome" msgid="2570923463033985887">"Дом."</string>
+    <string name="phoneTypeHome" msgid="2570923463033985887">"Домашній"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Мобільний"</string>
-    <string name="phoneTypeWork" msgid="8863939667059911633">"Роб."</string>
+    <string name="phoneTypeWork" msgid="8863939667059911633">"Робочий"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Роб. факс"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Дом. факс"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"Пейджер"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хоче ввімкнути функцію дослідження дотиком. Увімкнувши функцію дослідження дотиком, можна чути або бачити опис елемента, розташованого під вашим пальцем, або виконувати жести для взаємодії з телефоном."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 міс. тому"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раніше 1 місяця тому"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 сек. тому"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> сек. тому"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 хвилину тому"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> хв. тому"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 год. тому"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> год. тому"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Остан. <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Останній міс."</string>
     <string name="older" msgid="5211975022815554840">"Давніше"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"учора"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. тому"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"через 1 сек."</item>
-    <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"через 1 хв."</item>
-    <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> хв."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"через 1 год."</item>
-    <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> год."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"завтра"</item>
-    <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 сек. тому"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. тому"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 хв. тому"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> хв. тому"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 годину тому"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> год. тому"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"учора"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. тому"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
-    <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"через 1 хв."</item>
-    <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> хв."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"через 1 год."</item>
-    <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> год."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"завтра"</item>
-    <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"о <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"у <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Запуск ОС Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Оптимізація пам’яті."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимізація програми <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Підготовка додатка <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск програм."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Завершення завантаження."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Працює <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s хоче під’єднатися до %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Додаток %1$s хоче під’єднатися до мережі Wi-Fi \"%2$s\""</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Додаток"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Запустити Wi-Fi Direct. Це вимкне з’єднання Wi-Fi клієнт/точка доступу."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Запит SS перетворено на запит DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Запит SS перетворено на запит USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Запит SS перетворено на новий запит SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Периферійний USB-порт"</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 7f8a88e..feecb77 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ہوائی جہاز وضع آن ہے"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ہوائی جہاز وضع آف ہے"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ترتیبات"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"‎999+‎"</string>
     <string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ٹچ کرکے دریافت کریں کو فعال کرنا چاہتی ہے۔ ٹچ کرکے دریافت کریں کے آن ہو جانے پر، آپ کو اپنی انگلی کے نیچے موجود چیزوں کی تفصیلات دکھائی یا سنائی دے سکتی ہیں یا آپ فون کے ساتھ تعامل کرنے کیلئے اشارے انجام دے سکتے ہیں۔"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 مہینہ پہلے"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 مہینہ سے زیادہ پہلے"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 سیکنڈ پہلے"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ پہلے"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 منٹ پہلے"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> منٹ پہلے"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 گھنٹہ پہلے"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے پہلے"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"آخری <xliff:g id="COUNT">%d</xliff:g> دن"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"پچھلے مہینے"</string>
     <string name="older" msgid="5211975022815554840">"پرانا"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"گزشتہ کل"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> دن پہلے"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 سیکنڈ میں"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 منٹ میں"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> منٹ میں"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 گھنٹہ میں"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے میں"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"آنے والا کل"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> دن میں"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 سیکنڈ پہلے"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 منٹ پہلے"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> منٹ پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 گھنٹہ پہلے"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"گزشتہ کل"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> دن پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 سیکنڈ میں"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 منٹ میں"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> منٹ میں"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 گھنٹہ میں"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے میں"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"آنے والا کل"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> دن میں"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> کو"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> میں"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏Android شروع ہو رہا ہے…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"اسٹوریج کو بہترین بنایا جا رہا ہے۔"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"ایپ <xliff:g id="NUMBER_0">%1$d</xliff:g> از <xliff:g id="NUMBER_1">%2$d</xliff:g> کو بہتر بنایا جا رہا ہے۔"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> تیار ہو رہی ہے۔"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ایپس شروع ہو رہی ہیں۔"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"بوٹ مکمل ہو رہا ہے۔"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> چل رہی ہے"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏Wi-Fi سے مربوط نہیں ہو سکا"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اس میں ایک کمزور انٹرنیٹ کنکشن ہے۔"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"‏%2$s سے ‎%1$s‎ منسلک ہونا چاہے گا"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏ایپلیکیشن ‎%1$s Wifi نیٹ ورک ‎%2$s سے منسلک ہونا چاہتی ہے"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"ایک ایپلیکیشن"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏Wi-Fi ڈائریکٹ"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏Wi-Fi ڈائرکٹ شروع کریں۔ یہ Wi-Fi کلائنٹ/ہاٹ اسپاٹ کو آف کردے گا۔"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏SS درخواست میں ترمیم کر کے DIAL درخواست بنا دی گئی ہے۔"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏SS درخواست میں ترمیم کر کے USSD درخواست بنا دی گئی ہے۔"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏SS درخواست میں ترمیم کر کے نئی SS درخواست بنا دی گئی ہے۔"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏USB پیرفرل پورٹ"</string>
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 306e4b2..721e9bc 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Parvoz usuli yoqilgan"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Parvoz rejimi o‘chirilgan"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Sozlamalar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ovozli yordam"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Qulflash"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> teginib o‘rganish xususiyatini yoqishni xohlamoqda. Bu xususiyat yoqilganda, barmog‘ingiz ostidagi elementlar ta‘rifini ko‘rishingiz yoki eshitishingiz mumkin yoki telefon bilan o‘zaro bog‘lanish uchun barmog‘ingiz bilan imo-ishorali harakatlarni bajaring."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 oy oldin"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 oydan oldinroq"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 soniya oldin"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> soniya oldin"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 daqiqa oldin"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> daqiqa oldin"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 soat oldin"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"O‘tgan <xliff:g id="COUNT">%d</xliff:g> kun"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"O‘tgan oy"</string>
     <string name="older" msgid="5211975022815554840">"Eskiroq"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"kecha"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 soniyada"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> soniyada"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 daqiqada"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> daqiqada"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 soatda"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> soatda"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ertaga"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> kunda"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 soniya oldin"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> soniya oldin"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 daq. oldin"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> daq. oldin"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 soat oldin"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"kecha"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 soniya da"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> soniya da"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 daq. da"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> daq. da"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 soatda"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> soatda"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ertaga"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> kunda"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>da"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>da"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>da"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ishga tushmoqda…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Xotira optimallashtirilmoqda."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ilovalar optimallashtirilmoqda (<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g>)."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> tayyorlanmoqda."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Ilovalar ishga tushirilmoqda."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Tizimni yuklashni tugatish."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ishlamoqda"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tezligi past Internetga ulangan."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s quyidagiga ulanmoqchi: %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ilovasi %2$s Wi-Fi tarmog‘iga ulanmoqchi"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Ilova"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct’ni ishga tushirish. Bu Wi-Fi mijoz/ulanish nuqtasini o‘chiradi."</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS so‘rovi DIAL so‘roviga o‘zgartirildi."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS so‘rovi USSD so‘roviga o‘zgartirildi."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS so‘rovi yangi SS so‘roviga o‘zgartirildi."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Tashqi USB porti"</string>
 </resources>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 3a735bf..8f5cf3b 100755
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
diff --git a/core/res/res/values-vi/donottranslate-cldr.xml b/core/res/res/values-vi/donottranslate-cldr.xml
index 3a735bf..8f5cf3b 100755
--- a/core/res/res/values-vi/donottranslate-cldr.xml
+++ b/core/res/res/values-vi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e361bad..9f7118e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Chế độ trên máy bay BẬT"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Chế độ trên máy bay TẮT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Cài đặt"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Trợ lý thoại"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Khóa ngay"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> muốn bật Khám phá bằng cách chạm. Khi Khám phá bằng cách chạm được bật, bạn có thể nghe hoặc xem mô tả dưới ngón tay bạn hoặc thực hiện cử chỉ để tương tác với điện thoại."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 tháng trước"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Trước 1 tháng trước"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 giây trước"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> giây trước"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 phút trước"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> phút trước"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 giờ trước"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> giờ trước"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Tháng trước"</string>
     <string name="older" msgid="5211975022815554840">"Cũ hơn"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"hôm qua"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"trong 1 giây"</item>
-    <item quantity="other" msgid="1241926116443974687">"trong <xliff:g id="COUNT">%d</xliff:g> giây"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"trong 1 phút"</item>
-    <item quantity="other" msgid="3330713936399448749">"trong <xliff:g id="COUNT">%d</xliff:g> phút"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"trong 1 giờ"</item>
-    <item quantity="other" msgid="547290677353727389">"trong <xliff:g id="COUNT">%d</xliff:g> giờ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ngày mai"</item>
-    <item quantity="other" msgid="5109449375100953247">"trong <xliff:g id="COUNT">%d</xliff:g> ngày"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 giây trước"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> giây trước"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 phút trước"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> phút trước"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 giờ trước"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> giờ trước"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"hôm qua"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"trong 1 giây"</item>
-    <item quantity="other" msgid="5495880108825805108">"trong <xliff:g id="COUNT">%d</xliff:g> giây"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"trong 1 phút"</item>
-    <item quantity="other" msgid="4216113292706568726">"trong <xliff:g id="COUNT">%d</xliff:g> phút"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"trong 1 giờ"</item>
-    <item quantity="other" msgid="3705373766798013406">"trong <xliff:g id="COUNT">%d</xliff:g> giờ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ngày mai"</item>
-    <item quantity="other" msgid="2973062968038355991">"trong <xliff:g id="COUNT">%d</xliff:g> ngày"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"vào <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"trong <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android đang khởi động..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Tối ưu hóa lưu trữ."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Đang tối ưu hóa ứng dụng <xliff:g id="NUMBER_0">%1$d</xliff:g> trong tổng số <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Đang chuẩn bị <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Khởi động ứng dụng."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Hoàn tất khởi động."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> đang hoạt động"</string>
@@ -1348,9 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for wifi_connect_alert_message (8930084523889618078) -->
-    <skip />
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Ứng dụng %1$s muốn kết nối với Mạng Wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Ứng dụng"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Khởi động Wi-Fi Direct. Việc này sẽ tắt hoạt động của ứng dụng khách/điểm phát sóng Wi-Fi."</string>
@@ -1881,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Yêu cầu SS được sửa đổi thành yêu cầu DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Yêu cầu SS được sửa đổi thành yêu cầu USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Yêu cầu SS được sửa đổi thành yêu cầu SS mới."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Cổng ngoại vi USB"</string>
 </resources>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 3eede32..307a1ea 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -23,7 +23,7 @@
 
     <!-- Only show settings item due to smaller real estate. -->
     <string-array translatable="false" name="config_globalActionsList">
-        <item>settings</item>
+        <item>voiceassist</item>
     </string-array>
 
     <!-- Base "touch slop" value used by ViewConfiguration as a
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
index b83f412..b3f009e 100755
--- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y 年 %-m 月 %-e 日</string>
     <string name="time_of_day">%p %I:%M:%S</string>
     <string name="date_and_time">%Y 年 %-m 月 %-e 日%p %I:%M:%S</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 4a03e7b..4d8db93 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -970,7 +971,7 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"重试"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"重试"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超过“人脸解锁”尝试次数上限"</string>
-    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有SIM卡"</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有 SIM 卡"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有SIM卡。"</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"电视中没有 SIM 卡。"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无SIM卡"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>想要启用“触摸浏览”。“触摸浏览”启用后,您可以听到或看到所触摸内容的说明,还可以通过手势操作与手机互动。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 个月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 个月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1分钟前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分钟前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1小时前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>小时前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"过去<xliff:g id="COUNT">%d</xliff:g>天"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"上个月"</string>
     <string name="older" msgid="5211975022815554840">"往前"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨天"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>天前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1秒后"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒后"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1分钟后"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分钟后"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1小时后"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>小时后"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明天"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1分钟前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分钟前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1小时前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>小时前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨天"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>天前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1秒后"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒后"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1分钟后"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分钟后"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1小时后"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>小时后"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明天"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"日期:<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"年份:<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android 正在启动…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"正在优化存储空间。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"正在优化第<xliff:g id="NUMBER_0">%1$d</xliff:g>个应用(共<xliff:g id="NUMBER_1">%2$d</xliff:g>个)。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"正在准备升级<xliff:g id="APPNAME">%1$s</xliff:g>。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在启动应用。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"即将完成启动。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>正在运行"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s想要连接到%2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"“%1$s”应用想要连接到 WLAN 网络“%2$s”"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"一款应用"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN直连"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动WLAN直连。此操作将会关闭WLAN客户端/热点。"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 请求已修改为 DIAL 请求。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 请求已修改为 USSD 请求。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 请求已修改为新的 SS 请求。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 外设端口"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index bb39491..d08a416 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛行模式為 [關閉]"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> 需要啟用「輕觸探索」。開啟這項功能時,系統會在您的手指輕觸螢幕上的物件時顯示或朗讀說明,您也可以執行手勢來與手機互動。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 秒前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 分鐘前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 小時前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"最近 <xliff:g id="COUNT">%d</xliff:g> 天"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"上個月"</string>
     <string name="older" msgid="5211975022815554840">"較舊"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨天"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 秒後"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> 秒後"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 分鐘後"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> 分鐘後"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 小時後"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時後"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明天"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天後"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 秒前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 分鐘前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 小時前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨天"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 秒後"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 分鐘後"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 小時後"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明天"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天後"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"於 <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"在 <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"於 <xliff:g id="YEAR">%s</xliff:g> 年"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android 正在啟動…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"正在優化儲存空間。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"正在優化第 <xliff:g id="NUMBER_0">%1$d</xliff:g> 個應用程式 (共 <xliff:g id="NUMBER_1">%2$d</xliff:g> 個)。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"正在準備 <xliff:g id="APPNAME">%1$s</xliff:g>。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在啟動應用程式。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"啟動完成。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"正在執行 <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互聯網連線欠佳。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s 要求連線至 %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"應用程式 %1$s 要求連線至 WiFi 網絡 %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 Wi-Fi Direct,這會關閉 Wi-Fi 使用者端/熱點。"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 要求已修改為 DIAL 要求。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 要求已修改為 USSD 要求。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 要求已修改為新的 SS 要求。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 外端連接埠"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
index 0a19896..3e2b33d 100755
--- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%Y 年 %-m 月 %-e 日</string>
     <string name="time_of_day">%p %I:%M:%S</string>
     <string name="date_and_time">%Y/%-m/%-e %p %I:%M:%S</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 507205a..24ccc9a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> 需要啟用「輕觸探索」。開啟這項功能時,系統會在您的手指輕觸螢幕上的物件時顯示或朗讀說明,您也可以執行手勢來與手機互動。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月以前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 秒以前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 分鐘以前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 小時以前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"最近 <xliff:g id="COUNT">%d</xliff:g> 天"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"上個月"</string>
     <string name="older" msgid="5211975022815554840">"較舊"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨天"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 秒內"</item>
-    <item quantity="other" msgid="1241926116443974687">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 分鐘內"</item>
-    <item quantity="other" msgid="3330713936399448749">"在 <xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 小時內"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明天"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 秒以前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 分鐘以前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 小時以前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨天"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 秒內"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 分鐘內"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 小時內"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明天"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"於 <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"於<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"於 <xliff:g id="YEAR">%s</xliff:g> 年"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android 正在啟動…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"正在對儲存空間進行最佳化處理。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"正在最佳化第 <xliff:g id="NUMBER_0">%1$d</xliff:g> 個應用程式 (共 <xliff:g id="NUMBER_1">%2$d</xliff:g> 個)。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"正在準備升級「<xliff:g id="APPNAME">%1$s</xliff:g>」。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在啟動應用程式。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"啟動完成。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 執行中"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"%1$s 要求連線至 %2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"「%1$s」應用程式要求連線至 WiFi 網路 %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 Wi-Fi Direct 作業,這會關閉 Wi-Fi 用戶端/無線基地台作業。"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 要求已改為 DIAL 要求。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 要求已改為 USSD 要求。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 要求已改為新的 SS 要求。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 週邊連接埠"</string>
 </resources>
diff --git a/core/res/res/values-zu/donottranslate-cldr.xml b/core/res/res/values-zu/donottranslate-cldr.xml
index 087ad833..e2cf516 100755
--- a/core/res/res/values-zu/donottranslate-cldr.xml
+++ b/core/res/res/values-zu/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %-e %b %Y</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1222904..881b544 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -200,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Imodi yendiza IVULIWE"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Imodi yendiza IVALIWE"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Izilungiselelo"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Isisekeli sezwi"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Khiya manje"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
@@ -1130,75 +1131,9 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"I-<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ifuna ukunika amandla i-Explore by Touch. Uma i-Explore by Touch ikhanya, ungezwa noma ubone izincazelo ezingaphansi komunwe wakho noma wenze izenzo zomzimba ukuze uxhumane nefoni."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"inyanga engu-1 edlule"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ngaphambi kwenyanga engu-1 edlule"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 isekhondi eledlule"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> amasekhondi adlule"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 iminithi elidlule"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule.."</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ihora eledlule"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> amahora adlule"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Izinsuku zokugcina ezingu- <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <!-- no translation found for last_num_days:one (7555846096746489821) -->
     <string name="last_month" msgid="3959346739979055432">"Inyanga edlule"</string>
     <string name="older" msgid="5211975022815554840">"Okudala kakhulu"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"Izolo"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> izinsuku ezedlule"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"esekhondini elingu-1"</item>
-    <item quantity="other" msgid="1241926116443974687">"emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"eminithini engu-1"</item>
-    <item quantity="other" msgid="3330713936399448749">"emaminithini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ehoreni elingu-1"</item>
-    <item quantity="other" msgid="547290677353727389">"emahoreni angu- <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"Kusasa"</item>
-    <item quantity="other" msgid="5109449375100953247">"ezinsukwini ezingu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 isekhondi edlule"</item>
-    <item quantity="other" msgid="3699169366650930415">"amasekhondi angu-<xliff:g id="COUNT">%d</xliff:g> edlule"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 iminithi eledlule"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ihora eledlule"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> amahora adlule"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"Izolo"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> izinsuku ezedlule"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"esekhondini elingu-1"</item>
-    <item quantity="other" msgid="5495880108825805108">"emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"eminithini engu-1"</item>
-    <item quantity="other" msgid="4216113292706568726">"emaminithini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ehoreni elingu-1"</item>
-    <item quantity="other" msgid="3705373766798013406">"emahoreni angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"Kusasa"</item>
-    <item quantity="other" msgid="2973062968038355991">"ezinsukwini ezing-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"e-<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"phakathi- <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1303,6 +1238,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"I-Android iyaqala…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Ikhulisa isitoreji."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ukubeka ezingeni eliphezulu <xliff:g id="NUMBER_0">%1$d</xliff:g> uhlelo lokusebenza <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Ukulungisela i-<xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinhlelo zokusebenza."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Qedela ukuqala kabusha."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> iyasebenza"</string>
@@ -1348,7 +1284,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
-    <string name="wifi_connect_alert_message" msgid="8930084523889618078">"U-%1$s angathanda ukuxhumeka ku-%2$s"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Uhlelo lokusebenza %1$s lungathanda ukuxhuma kunethiwekhi ye-Wifi %2$s"</string>
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Uhlelo lokusebenza"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-Wi-Fi Eqondile"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Qala ukusebenza kwe-Wi-Fi Okuqondile. Lokhu kuzocima ikhasimende le-Wi-Fi/Ukusebenza okwe-hotspot"</string>
@@ -1879,4 +1815,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Isicelo se-SS siguqulelwe kusicelo se-DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Isicelo se-SS siguqulelwe kusicelo se-USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Isicelo se-SS siguqulelwe kusicelo esisha se-SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"I-Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Imbobo ye-USB Peripheral"</string>
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f6a5787..3312f4f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -302,7 +302,6 @@
        <item>@drawable/ab_solid_shadow_material</item>
        <item>@drawable/activated_background_material</item>
        <item>@drawable/btn_borderless_material</item>
-       <item>@drawable/btn_cab_done_material</item>
        <item>@drawable/btn_check_material_anim</item>
        <item>@drawable/btn_default_material</item>
        <item>@drawable/btn_radio_material_anim</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 39c42ee..b90ac65 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1952,6 +1952,16 @@
 
         <!-- Whether to clip window content to the outline of the window background. -->
         <attr name="windowClipToOutline" format="boolean" />
+
+        <!-- If set, the status bar will be drawn such that it is compatible with a light
+             status bar background.
+             <p>For this to take effect, the window must be drawing the system bar backgrounds with
+             {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the status bar must not
+             have been requested to be translucent with
+             {@link android.R.attr#windowTranslucentStatus}.
+             Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_STATUS_BAR} on
+             the decor view. -->
+        <attr name="windowHasLightStatusBar" format="boolean" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2631,6 +2641,8 @@
     <declare-styleable name="Include">
         <attr name="id" />
         <attr name="visibility" />
+        <attr name="layout_width" />
+        <attr name="layout_height" />
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -4338,6 +4350,10 @@
         <attr name="popupAnimationStyle" format="reference" />
         <!-- Whether the popup window should overlap its anchor view. -->
         <attr name="overlapAnchor" format="boolean" />
+        <!-- Transition used to move views into the popup window. -->
+        <attr name="popupEnterTransition" format="reference" />
+        <!-- Transition used to move views out of the popup window. -->
+        <attr name="popupExitTransition" format="reference" />
     </declare-styleable>
     <declare-styleable name="ListPopupWindow">
         <!-- Amount of pixels by which the drop down should be offset vertically. -->
@@ -5074,14 +5090,31 @@
 
     <!-- Describes an item (or child) of a LayerDrawable. -->
     <declare-styleable name="LayerDrawableItem">
-        <!-- Left coordinate of the layer. -->
+        <!-- Left inset to apply to the layer. -->
         <attr name="left" />
-        <!-- Top coordinate of the layer. -->
+        <!-- Top inset to apply to the layer. -->
         <attr name="top" />
-        <!-- Right coordinate of the layer. -->
+        <!-- Right inset to apply to the layer. -->
         <attr name="right" />
-        <!-- Bottom coordinate of the layer. -->
+        <!-- Bottom inset to apply to the layer. -->
         <attr name="bottom" />
+        <!-- Start inset to apply to the layer. Overrides {@code left} or
+             {@code right} depending on layout direction. -->
+        <attr name="start" format="dimension" />
+        <!-- End inset to apply to the layer. Overrides {@code left} or
+             {@code right} depending on layout direction. -->
+        <attr name="end" format="dimension" />
+        <!-- Width of the layer. Defaults to the layer's intrinsic width. -->
+        <attr name="width" />
+        <!-- Height of the layer. Defaults to the layer's intrinsic height -->
+        <attr name="height" />
+        <!-- Gravity used to align the layer within its container. If no value
+             is specified, the default behavior depends on whether an explicit
+             width or height has been set, If no dimension is set, gravity in
+             that direction defaults to {@code fill_horizontal} or
+             {@code fill_vertical}; otherwise, it defaults to {@code left} or
+             {@code top}. -->
+        <attr name="gravity" />
         <!-- Drawable used to render the layer. -->
         <attr name="drawable" />
         <!-- Identifier of the layer. This can be used to retrieve the layer
@@ -5963,11 +5996,11 @@
              set when a view is enabled. -->
         <attr name="state_enabled" format="boolean" />
         <!-- State identifier indicating that the object <var>may</var> display a check mark.
-             See {@link R.attr#state_checked} for the identifier that indicates whether it is
+             See {@link android.R.attr#state_checked} for the identifier that indicates whether it is
              actually checked. -->
         <attr name="state_checkable" format="boolean"/>
         <!-- State identifier indicating that the object is currently checked.  See
-             {@link R.attr#state_checkable} for an additional identifier that can indicate if
+             {@link android.R.attr#state_checkable} for an additional identifier that can indicate if
              any object may ever display a check, regardless of whether state_checked is
              currently set. -->
         <attr name="state_checked" format="boolean"/>
@@ -7257,8 +7290,34 @@
     <declare-styleable name="Switch">
         <!-- Drawable to use as the "thumb" that switches back and forth. -->
         <attr name="thumb" />
+        <!-- Tint to apply to the thumb. -->
+        <attr name="thumbTint" />
+        <!-- Blending mode used to apply the thumb tint. -->
+        <attr name="thumbTintMode" />
         <!-- Drawable to use as the "track" that the switch thumb slides within. -->
         <attr name="track" format="reference" />
+        <!-- Tint to apply to the track. -->
+        <attr name="trackTint" format="color" />
+        <!-- Blending mode used to apply the track tint. -->
+        <attr name="trackTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
         <!-- Text to use when the switch is in the checked/"on" state. -->
         <attr name="textOn" />
         <!-- Text to use when the switch is in the unchecked/"off" state. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0c3fb9a..9678322 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1012,6 +1012,24 @@
          <p>The default value of this attribute is <code>false</code>. -->
     <attr name="resumeWhilePausing" format="boolean" />
 
+    <!-- Indicates that it is okay for this activity to be resized to any dimension. Intended for a
+         multi-window device where there can be multiple activities of various sizes on the screen
+         at the same time.
+
+         <p>The default value is <code>false</code> for applications with
+         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#MNC} and
+         <code>true</code> otherwise.
+
+         <p>NOTE: A task's root activity value is applied to all additional activities launched in
+         the task. That is if the root activity of a task is resizeable then the system will treat
+         all other activities in the task as resizeable and will not if the root activity isn't
+         resizeable.
+
+         <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
+         resizeable activities as the system doesn't support fixed orientation on a resizeable
+         activity. -->
+    <attr name="resizeableActivity" format="boolean" />
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -1020,7 +1038,7 @@
          to avoid name collisions.  For example, applications published
          by Google could have names of the form
          <code>com.google.app.<em>appname</em></code>
-         
+
          <p>Inside of the manifest tag, may appear the following tags
          in any order: {@link #AndroidManifestPermission permission},
          {@link #AndroidManifestPermissionGroup permission-group},
@@ -1039,7 +1057,7 @@
         <attr name="sharedUserLabel" />
         <attr name="installLocation" />
     </declare-styleable>
-    
+
     <!-- The <code>application</code> tag describes application-level components
          contained in the package, as well as general application
          attributes.  Many of the attributes you can supply here (such
@@ -1047,7 +1065,7 @@
          and allowTaskReparenting) serve
          as default values for the corresponding attributes of components
          declared inside of the application.
-         
+
          <p>Inside of this element you specify what the application contains,
          using the elements {@link #AndroidManifestProvider provider},
          {@link #AndroidManifestService service},
@@ -1698,6 +1716,7 @@
         <attr name="autoRemoveFromRecents" />
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
+        <attr name="resizeableActivity" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 457131a..7c63950 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -25,4 +25,8 @@
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="action_bar_expanded_action_views_exclusive">true</bool>
     <bool name="target_honeycomb_needs_options_menu">true</bool>
+
+    <!-- Whether to allow vertically stacked button bars. This is disabled for
+         configurations with a small (e.g. less than 320dp) screen height. -->
+    <bool name="allow_stacked_button_bar">false</bool>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3843d16..4c25e7d 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -424,6 +424,10 @@
     <!-- Integer indicating wpa_supplicant scan interval in milliseconds -->
     <integer translatable="false" name="config_wifi_supplicant_scan_interval">15000</integer>
 
+    <!-- Integer indicating amount of time failed networks areblacklisted for the purpose
+         of network switching in milliseconds -->
+    <integer translatable="false" name="config_wifi_network_switching_blacklist_time">172800000</integer>
+
     <!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
     <integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
 
@@ -628,6 +632,14 @@
          Any other values will have surprising consequences. -->
     <integer name="config_defaultUiModeType">1</integer>
 
+    <!-- Control the default night mode to use when there is no other mode override set.
+         One of the following values (see UiModeManager.java):
+             0 - MODE_NIGHT_AUTO
+             1 - MODE_NIGHT_NO
+             2 - MODE_NIGHT_YES
+    -->
+    <integer name="config_defaultNightMode">1</integer>
+
     <!-- Indicate whether to allow the device to suspend when the screen is off
          due to the proximity sensor.  This resource should only be set to true
          if the sensor HAL correctly handles the proximity sensor as a wake-up source.
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index e1e1ffed..1975875 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -114,4 +114,6 @@
 
     <!-- Padding above and below selection dialog lists. -->
     <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
+
+    <dimen name="progress_bar_height_material">4dp</dimen>
 </resources>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index 80db6e4..a8e2b2b 100755
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?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="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%B %-e, %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9945c63..3ac7374 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2608,6 +2608,29 @@
        =============================================================== -->
   <eat-comment />
 
+  <public type="attr" name="trackTint" />
+  <public type="attr" name="trackTintMode" />
+  <public type="attr" name="resizeableActivity" />
+  <public type="attr" name="start" />
+  <public type="attr" name="end" />
+  <public type="attr" name="windowHasLightStatusBar" />
+
   <public type="style" name="Widget.Material.Button.Colored" />
 
+  <public type="style" name="Theme.Material.DayNight" />
+  <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
+  <public type="style" name="Theme.Material.DayNight.Dialog" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.Alert" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
+  <public type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
+  <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
+  <public type="style" name="Theme.Material.DayNight.Panel" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f51e82c9..ff03ca9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -482,6 +482,9 @@
     <!-- label for item that launches settings in phone options dialog [CHAR LIMIT=15]-->
     <string name="global_action_settings">Settings</string>
 
+    <!-- label for item that launches voice assist in phone options dialog [CHAR LIMIT=15]-->
+    <string name="global_action_voice_assist">Voice Assist</string>
+
     <!-- label for item that locks the phone and enforces that it can't be unlocked without entering a credential. [CHAR LIMIT=15] -->
     <string name="global_action_lockdown">Lock now</string>
 
@@ -3377,26 +3380,9 @@
     <!-- String used to display the date. This is the string to say something happened more than 1 month ago. -->
     <string name="beforeOneMonthDurationPast">Before 1 month ago</string>
 
-    <!-- This is used to express that something occurred some number of seconds in the past (e.g., 5 seconds ago). -->
-    <plurals name="num_seconds_ago">
-        <item quantity="one">1 second ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of minutes in the past (e.g., 5 minutes ago). -->
-    <plurals name="num_minutes_ago">
-        <item quantity="one">1 minute ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of hours in the past (e.g., 5 hours ago). -->
-    <plurals name="num_hours_ago">
-        <item quantity="one">1 hour ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
-    </plurals>
-
     <!-- This is used to express that something occurred within the last X days (e.g., Last 7 days). -->
     <plurals name="last_num_days">
+        <item quantity="one">Last <xliff:g id="count">%d</xliff:g> day</item>
         <item quantity="other">Last <xliff:g id="count">%d</xliff:g> days</item>
     </plurals>
 
@@ -3406,84 +3392,6 @@
     <!-- This is used to express that something happened longer ago than the previous options -->
     <string name="older">Older</string>
 
-    <!-- This is used to express that something occurred some number of days in the past (e.g., 5 days ago). -->
-    <plurals name="num_days_ago">
-        <item quantity="one">yesterday</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of seconds in the future (e.g., in 5 seconds). -->
-    <plurals name="in_num_seconds">
-        <item quantity="one">in 1 second</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> seconds</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of minutes in the future (e.g., in 5 minutes). -->
-    <plurals name="in_num_minutes">
-        <item quantity="one">in 1 minute</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> minutes</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of hours in the future (e.g., in 5 hours). -->
-    <plurals name="in_num_hours">
-        <item quantity="one">in 1 hour</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of days in the future (e.g., in 5 days). -->
-    <plurals name="in_num_days">
-        <item quantity="one">tomorrow</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated seconds in the past (e.g., 5 secs ago). -->
-    <plurals name="abbrev_num_seconds_ago">
-        <item quantity="one">1 sec ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> secs ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated minutes in the past (e.g., 5 mins ago). -->
-    <plurals name="abbrev_num_minutes_ago">
-        <item quantity="one">1 min ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> mins ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated hours in the past (e.g., 5 hrs ago). -->
-    <plurals name="abbrev_num_hours_ago">
-        <item quantity="one">1 hour ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated days in the past (e.g., 5 days ago). -->
-    <plurals name="abbrev_num_days_ago">
-        <item quantity="one">yesterday</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated seconds in the future (e.g., in 5 secs). -->
-    <plurals name="abbrev_in_num_seconds">
-        <item quantity="one">in 1 sec</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> secs</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated minutes in the future (e.g., in 5 mins). -->
-    <plurals name="abbrev_in_num_minutes">
-        <item quantity="one">in 1 min</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> mins</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated hours in the future (e.g., in 5 hrs). -->
-    <plurals name="abbrev_in_num_hours">
-        <item quantity="one">in 1 hour</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated days in the future (e.g., in 5 days). -->
-    <plurals name="abbrev_in_num_days">
-        <item quantity="one">tomorrow</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
-    </plurals>
-
     <!-- String used to display the date. Preposition for date display ("on May 29") -->
     <string name="preposition_for_date">on <xliff:g id="date" example="May 29">%s</xliff:g></string>
     <!-- String used to display the date. Preposition for time display ("at 2:33am") -->
@@ -3748,6 +3656,9 @@
         <xliff:g id="number" example="123">%1$d</xliff:g> of
         <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
 
+    <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog for each .apk pre boot broadcast -->
+    <string name="android_preparing_apk">Preparing <xliff:g id="appname">%1$s</xliff:g>.</string>
+
     <!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when reached the point of starting apps. -->
     <string name="android_upgrading_starting_apps">Starting apps.</string>
 
@@ -3853,7 +3764,7 @@
     <!-- title for this message -->
     <string name="wifi_connect_alert_title">Allow connection?</string>
     <!-- message explaining who is connecting to what -->
-    <string name="wifi_connect_alert_message">%1$s would like to connect to %2$s</string>
+    <string name="wifi_connect_alert_message">Application %1$s would like to connect to Wifi Network %2$s</string>
     <!-- default application in case name can not be found -->
     <string name="wifi_connect_default_application">An application</string>
 
@@ -5188,4 +5099,9 @@
     <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
     <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
 
+    <!-- Manufacturer name for USB MIDI Peripheral port -->
+    <string name="usb_midi_peripheral_manufacturer_name">Android</string>
+    <!-- Model name for USB MIDI Peripheral port -->
+    <string name="usb_midi_peripheral_model_name">USB Peripheral Port</string>
+
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 4329809..777924f 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -88,7 +88,7 @@
     </style>
 
     <style name="Preference.Material.DialogPreference.EditTextPreference">
-        <item name="dialogLayout">@layout/preference_dialog_edittext</item>
+        <item name="dialogLayout">@layout/preference_dialog_edittext_material</item>
     </style>
 
     <style name="Preference.Material.RingtonePreference">
@@ -464,7 +464,7 @@
 
     <!-- Colored bordered ink button -->
     <style name="Widget.Material.Button.Colored">
-        <item name="backgroundTint">@color/btn_material_accent</item>
+        <item name="backgroundTint">@color/btn_colored_material</item>
     </style>
 
     <!-- Small bordered ink button -->
@@ -481,8 +481,7 @@
 
     <!-- Colored borderless ink button -->
     <style name="Widget.Material.Button.Borderless.Colored">
-        <item name="textColor">?attr/colorAccent</item>
-        <item name="stateListAnimator">@anim/disabled_anim_material</item>
+        <item name="textColor">@color/btn_colored_text_material</item>
     </style>
 
     <!-- Alert dialog button bar button -->
@@ -770,6 +769,9 @@
         <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
         <item name="popupBackground">@drawable/popup_background_material</item>
         <item name="popupElevation">@dimen/floating_window_z</item>
+        <item name="popupAnimationStyle">@empty</item>
+        <item name="popupEnterTransition">@transition/popup_window_enter</item>
+        <item name="popupExitTransition">@transition/popup_window_exit</item>
         <item name="dropDownVerticalOffset">0dip</item>
         <item name="dropDownHorizontalOffset">0dip</item>
         <item name="overlapAnchor">true</item>
@@ -780,11 +782,7 @@
     </style>
 
     <style name="Widget.Material.Spinner.DropDown"/>
-
-    <style name="Widget.Material.Spinner.DropDown.ActionBar">
-        <item name="background">@drawable/spinner_background_material</item>
-        <item name="overlapAnchor">true</item>
-    </style>
+    <style name="Widget.Material.Spinner.DropDown.ActionBar" />
 
     <style name="Widget.Material.Spinner.Underlined">
         <item name="background">@drawable/spinner_textfield_background_material</item>
@@ -847,7 +845,9 @@
         <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
         <item name="popupBackground">@drawable/popup_background_material</item>
         <item name="popupElevation">@dimen/floating_window_z</item>
-        <item name="popupAnimationStyle">@style/Animation.Material.Popup</item>
+        <item name="popupAnimationStyle">@empty</item>
+        <item name="popupEnterTransition">@transition/popup_window_enter</item>
+        <item name="popupExitTransition">@transition/popup_window_exit</item>
         <item name="dropDownVerticalOffset">0dip</item>
         <item name="dropDownHorizontalOffset">0dip</item>
         <item name="dropDownWidth">wrap_content</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f6d39a7..85fd448 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -327,6 +327,7 @@
   <java-symbol type="integer" name="config_wifi_framework_scan_result_rssi_level_patchup_value" />
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="string"  name="config_wifi_random_mac_oui" />
+  <java-symbol type="integer"  name="config_wifi_network_switching_blacklist_time" />
 
   <java-symbol type="bool" name="editable_voicemailnumber" />
 
@@ -707,7 +708,6 @@
   <java-symbol type="string" name="noon" />
   <java-symbol type="string" name="number_picker_increment_scroll_action" />
   <java-symbol type="string" name="number_picker_increment_scroll_mode" />
-  <java-symbol type="string" name="numeric_date_template" />
   <java-symbol type="string" name="old_app_action" />
   <java-symbol type="string" name="old_app_description" />
   <java-symbol type="string" name="older" />
@@ -1057,27 +1057,11 @@
   <java-symbol type="string" name="config_ethernet_tcp_buffers" />
   <java-symbol type="string" name="config_wifi_tcp_buffers" />
 
-  <java-symbol type="plurals" name="abbrev_in_num_days" />
-  <java-symbol type="plurals" name="abbrev_in_num_hours" />
-  <java-symbol type="plurals" name="abbrev_in_num_minutes" />
-  <java-symbol type="plurals" name="abbrev_in_num_seconds" />
-  <java-symbol type="plurals" name="abbrev_num_days_ago" />
-  <java-symbol type="plurals" name="abbrev_num_hours_ago" />
-  <java-symbol type="plurals" name="abbrev_num_minutes_ago" />
-  <java-symbol type="plurals" name="abbrev_num_seconds_ago" />
   <java-symbol type="plurals" name="duration_hours" />
   <java-symbol type="plurals" name="duration_minutes" />
   <java-symbol type="plurals" name="duration_seconds" />
-  <java-symbol type="plurals" name="in_num_days" />
-  <java-symbol type="plurals" name="in_num_hours" />
-  <java-symbol type="plurals" name="in_num_minutes" />
-  <java-symbol type="plurals" name="in_num_seconds" />
   <java-symbol type="plurals" name="last_num_days" />
   <java-symbol type="plurals" name="matches_found" />
-  <java-symbol type="plurals" name="num_days_ago" />
-  <java-symbol type="plurals" name="num_hours_ago" />
-  <java-symbol type="plurals" name="num_minutes_ago" />
-  <java-symbol type="plurals" name="num_seconds_ago" />
   <java-symbol type="plurals" name="restr_pin_countdown" />
   <java-symbol type="plurals" name="pinpuk_attempts" />
 
@@ -1513,6 +1497,7 @@
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
   <java-symbol type="string" name="system_ui_date_pattern" />
+  <java-symbol type="string" name="android_preparing_apk" />
   <java-symbol type="string" name="android_start_title" />
   <java-symbol type="string" name="android_upgrading_title" />
   <java-symbol type="string" name="bugreport_title" />
@@ -1529,6 +1514,7 @@
   <java-symbol type="string" name="global_action_silent_mode_on_status" />
   <java-symbol type="string" name="global_action_toggle_silent_mode" />
   <java-symbol type="string" name="global_action_lockdown" />
+  <java-symbol type="string" name="global_action_voice_assist" />
   <java-symbol type="string" name="invalidPuk" />
   <java-symbol type="string" name="lockscreen_carrier_default" />
   <java-symbol type="style" name="Animation.LockScreen" />
@@ -1616,6 +1602,7 @@
   <java-symbol type="drawable" name="ic_notification_ime_default" />
   <java-symbol type="drawable" name="ic_menu_refresh" />
   <java-symbol type="drawable" name="ic_settings" />
+  <java-symbol type="drawable" name="ic_voice_search" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled_data" />
   <java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -2155,4 +2142,14 @@
   <java-symbol type="bool" name="config_use_sim_language_file" />
   <java-symbol type="bool" name="config_LTE_eri_for_network_name" />
   <java-symbol type="bool" name="config_defaultInTouchMode" />
+
+  <java-symbol type="string" name="usb_midi_peripheral_manufacturer_name" />
+  <java-symbol type="string" name="usb_midi_peripheral_model_name" />
+
+  <java-symbol type="bool" name="allow_stacked_button_bar" />
+  <java-symbol type="id" name="spacer" />
+
+  <java-symbol type="xml" name="bookmarks" />
+
+  <java-symbol type="integer" name="config_defaultNightMode" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 2b8ed5f..57041fdd 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1238,8 +1238,7 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1251,8 +1250,7 @@
         <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
     </style>
 
-    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1260,8 +1258,7 @@
 
     <style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
 
-    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1269,22 +1266,19 @@
 
     <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
 
-    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
     </style>
 
-    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
     </style>
 
-    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
new file mode 100644
index 0000000..5d9b860
--- /dev/null
+++ b/core/res/res/values/themes_material_daynight.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+
+    <!-- Material theme (day/night vesion) for activities. -->
+    <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
+
+    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
+         with an inverse color profile. The dark action bar sharply stands out against
+         the light content (when applicable).  -->
+    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
+
+    <!-- Variant of Material.DayNight with no action bar.  -->
+    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen. This theme
+         sets {@link android.R.attr#windowFullscreen} to true.  -->
+    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen and extends into the display overscan region. This theme
+         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+         to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
+
+    <!-- Variant of Material.DayNight that has no title bar and translucent
+         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+         {@link android.R.attr#windowTranslucentNavigation} to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
+
+    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
+         window decorations, so you basically have an empty rectangle in which
+         to place your content. It makes the window floating, with a transparent
+         background, and turns off dimming behind the window. -->
+    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
+
+    <!-- Material theme (day/night vesion) for dialog windows and activities,
+         which is used by the {@link android.app.Dialog} class. This changes
+         the window to be floating (not fill the entire screen), and puts a
+         frame around its contents. You can set this theme on an activity if
+         you would like to make an activity that looks like a Dialog. -->
+    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
+    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+
+    <!-- Theme for a window that will be displayed either full-screen on
+         smaller screens (small, normal) or as a dialog on larger screens
+         (large, xlarge). -->
+    <style name="Theme.Material.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
+
+    <!-- Theme for a window without an action bar that will be displayed either full-screen
+         on smaller screens (small, normal) or as a dialog on larger screens
+         (large, xlarge). -->
+    <style name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
+
+    <!-- Theme for a presentation window on a secondary display. -->
+    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
+
+    <!-- Material user theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class. -->
+    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
+    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
+
+    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
+    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
+
+</resources>
diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml
new file mode 100644
index 0000000..454f456
--- /dev/null
+++ b/core/res/res/xml/bookmarks.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+     Default system bookmarks for AOSP.
+     Bookmarks for vendor apps should be added to a bookmarks resource overlay; not here.
+
+     Typical shortcuts (not necessarily defined here):
+       'a': Calculator
+       'b': Browser
+       'c': Contacts
+       'e': Email
+       'g': GMail
+       'l': Calendar
+       'm': Maps
+       'p': Music
+       's': SMS
+       't': Talk
+       'y': YouTube
+-->
+<bookmarks>
+    <bookmark
+        category="android.intent.category.APP_CALCULATOR"
+        shortcut="a" />
+    <bookmark
+        category="android.intent.category.APP_BROWSER"
+        shortcut="b" />
+    <bookmark
+        category="android.intent.category.APP_CONTACTS"
+        shortcut="c" />
+    <bookmark
+        category="android.intent.category.APP_EMAIL"
+        shortcut="e" />
+    <bookmark
+        category="android.intent.category.APP_CALENDAR"
+        shortcut="l" />
+    <bookmark
+        category="android.intent.category.APP_MAPS"
+        shortcut="m" />
+    <bookmark
+        category="android.intent.category.APP_MUSIC"
+        shortcut="p" />
+    <bookmark
+        category="android.intent.category.APP_MESSAGING"
+        shortcut="s" />
+</bookmarks>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7804dd2..18c83b4 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -75,7 +75,7 @@
     <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
 
     <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
-    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}" />
+    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215" />
 
     <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
     <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index dc43a2f..a59581b 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -425,7 +425,7 @@
             if (rLoc == INSTALL_LOC_INT) {
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
-                            (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                     assertStartsWith("The APK path should point to the ASEC",
                             SECURE_CONTAINERS_PREFIX, srcPath);
                     assertStartsWith("The public APK path should point to the ASEC",
@@ -441,7 +441,8 @@
                         fail("compat check: Can't read " + info.dataDir + "/lib");
                     }
                 } else {
-                    assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                    assertFalse(
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                     assertEquals(appInstallPath, srcPath);
                     assertEquals(appInstallPath, publicSrcPath);
                     assertStartsWith("Native library should point to shared lib directory",
@@ -467,16 +468,16 @@
             } else if (rLoc == INSTALL_LOC_SD) {
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
-                            (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                 } else {
                     assertFalse("The application should not be installed forward locked",
-                            (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                 }
                 assertTrue("Application flags (" + info.flags
                         + ") should contain FLAG_EXTERNAL_STORAGE",
                         (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
                 // Might need to check:
-                // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
+                // ((info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0)
                 assertStartsWith("The APK path should point to the ASEC",
                         SECURE_CONTAINERS_PREFIX, srcPath);
                 assertStartsWith("The public APK path should point to the ASEC",
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index e7f4bad..e5a92bf 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -11,7 +11,7 @@
 
     public void testSmallList() throws Exception {
         final int objectCount = 100;
-        List<SmallObject> list = new ArrayList<>();
+        List<SmallObject> list = new ArrayList<SmallObject>();
         for (int i = 0; i < objectCount; i++) {
             list.add(new SmallObject(i * 2, (i * 2) + 1));
         }
@@ -20,7 +20,7 @@
 
         Parcel parcel = Parcel.obtain();
         try {
-            parcel.writeParcelable(new ParceledListSlice<>(list), 0);
+            parcel.writeParcelable(new ParceledListSlice<SmallObject>(list), 0);
             parcel.setDataPosition(0);
             slice = parcel.readParcelable(getClass().getClassLoader());
         } finally {
@@ -56,7 +56,7 @@
         final int thresholdBytes = 256 * 1024;
         final int objectCount = thresholdBytes / measureLargeObject();
 
-        List<LargeObject> list = new ArrayList<>();
+        List<LargeObject> list = new ArrayList<LargeObject>();
         for (int i = 0; i < objectCount; i++) {
             list.add(new LargeObject(
                     i * 5,
@@ -71,7 +71,7 @@
 
         Parcel parcel = Parcel.obtain();
         try {
-            parcel.writeParcelable(new ParceledListSlice<>(list), 0);
+            parcel.writeParcelable(new ParceledListSlice<LargeObject>(list), 0);
             parcel.setDataPosition(0);
             slice = parcel.readParcelable(getClass().getClassLoader());
         } finally {
@@ -95,7 +95,7 @@
      * Test that only homogeneous elements may be unparceled.
      */
     public void testHomogeneousElements() throws Exception {
-        List<BaseObject> list = new ArrayList<>();
+        List<BaseObject> list = new ArrayList<BaseObject>();
         list.add(new LargeObject(0, 1, 2, 3, 4));
         list.add(new SmallObject(5, 6));
         list.add(new SmallObject(7, 8));
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
new file mode 100644
index 0000000..f9b69a0
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -0,0 +1,283 @@
+/*
+ * 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.content.pm;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.FileUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests for {@link android.content.pm.RegisteredServicesCache}
+ */
+public class RegisteredServicesCacheTest extends AndroidTestCase {
+
+    private final ResolveInfo r1 = new ResolveInfo();
+    private final ResolveInfo r2 = new ResolveInfo();
+    private final TestServiceType t1 = new TestServiceType("t1", "value1");
+    private final TestServiceType t2 = new TestServiceType("t2", "value2");
+    private File mDataDir;
+    private File mSyncDir;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        File cacheDir = mContext.getCacheDir();
+        mDataDir = new File(cacheDir, "testServicesCache");
+        FileUtils.deleteContents(mDataDir);
+        mSyncDir = new File(mDataDir, "system/registered_services");
+        mSyncDir.mkdirs();
+    }
+
+    public void testGetAllServicesHappyPath() {
+        TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+        cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+        cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2));
+        assertEquals(2, cache.getAllServicesSize(0));
+        assertEquals(2, cache.getPersistentServicesSize(0));
+        File file = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml");
+        assertTrue("File should be created at " + file, file.length() > 0);
+        // Make sure all services can be loaded from xml
+        cache = new TestServicesCache(mContext, mDataDir);
+        assertEquals(2, cache.getPersistentServicesSize(0));
+    }
+
+    public void testGetAllServicesReplaceUid() {
+        TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+        cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+        cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2));
+        cache.getAllServices(0);
+        // Invalidate cache and clear update query results
+        cache.invalidateCache(0);
+        cache.clearServicesForQuerying();
+        cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+        cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null,
+                TestServicesCache.SYSTEM_IMAGE_UID));
+        Collection<RegisteredServicesCache.ServiceInfo<TestServiceType>> allServices = cache
+                .getAllServices(0);
+        assertEquals(2, allServices.size());
+        Set<Integer> uids = new HashSet<>();
+        for (RegisteredServicesCache.ServiceInfo<TestServiceType> srv : allServices) {
+            uids.add(srv.uid);
+        }
+        assertTrue("UID must be updated to the new value",
+                uids.contains(TestServicesCache.SYSTEM_IMAGE_UID));
+        assertFalse("UID must be updated to the new value", uids.contains(2));
+    }
+
+    public void testGetAllServicesServiceRemoved() {
+        TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+        cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+        cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2));
+        assertEquals(2, cache.getAllServicesSize(0));
+        assertEquals(2, cache.getPersistentServicesSize(0));
+        // Re-read data from disk and verify services were saved
+        cache = new TestServicesCache(mContext, mDataDir);
+        assertEquals(2, cache.getPersistentServicesSize(0));
+        // Now register only one service and verify that another one is removed
+        cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1));
+        assertEquals(1, cache.getAllServicesSize(0));
+        assertEquals(1, cache.getPersistentServicesSize(0));
+    }
+
+    public void testGetAllServicesMultiUser() {
+        TestServicesCache cache = new TestServicesCache(mContext, mDataDir);
+        int u0 = 0;
+        int u1 = 1;
+        int pid1 = 1;
+        cache.addServiceForQuerying(u0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null,
+                pid1));
+        int u1uid = UserHandle.getUid(u1, 0);
+        cache.addServiceForQuerying(u1, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null,
+                u1uid));
+        assertEquals(u1, cache.getAllServicesSize(u0));
+        assertEquals(u1, cache.getPersistentServicesSize(u0));
+        assertEquals(u1, cache.getAllServicesSize(u1));
+        assertEquals(u1, cache.getPersistentServicesSize(u1));
+        assertEquals("No services should be available for user 3", 0, cache.getAllServicesSize(3));
+        // Re-read data from disk and verify services were saved
+        cache = new TestServicesCache(mContext, mDataDir);
+        assertEquals(u1, cache.getPersistentServicesSize(u0));
+        assertEquals(u1, cache.getPersistentServicesSize(u1));
+    }
+
+    /**
+     * Mock implementation of {@link android.content.pm.RegisteredServicesCache} for testing
+     */
+    private static class TestServicesCache extends RegisteredServicesCache<TestServiceType> {
+        static final String SERVICE_INTERFACE = "RegisteredServicesCacheTest";
+        static final String SERVICE_META_DATA = "RegisteredServicesCacheTest";
+        static final String ATTRIBUTES_NAME = "test";
+        // Represents UID of a system image process
+        static final int SYSTEM_IMAGE_UID = 20;
+        private SparseArray<Map<ResolveInfo, ServiceInfo<TestServiceType>>> mServices
+                = new SparseArray<>();
+
+        public TestServicesCache(Context context, File dir) {
+            super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME,
+                    new TestSerializer(), dir);
+        }
+
+        @Override
+        public TestServiceType parseServiceAttributes(Resources res, String packageName,
+                AttributeSet attrs) {
+            return null;
+        }
+
+        @Override
+        protected List<ResolveInfo> queryIntentServices(int userId) {
+            Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices
+                    .get(userId, new HashMap<ResolveInfo, ServiceInfo<TestServiceType>>());
+            return new ArrayList<>(map.keySet());
+        }
+
+        void addServiceForQuerying(int userId, ResolveInfo resolveInfo,
+                ServiceInfo<TestServiceType> serviceInfo) {
+            Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.get(userId);
+            if (map == null) {
+                map = new HashMap<>();
+                mServices.put(userId, map);
+            }
+            map.put(resolveInfo, serviceInfo);
+        }
+
+        void clearServicesForQuerying() {
+            mServices.clear();
+        }
+
+        int getPersistentServicesSize(int user) {
+            return getPersistentServices(user).size();
+        }
+
+        int getAllServicesSize(int user) {
+            return getAllServices(user).size();
+        }
+
+        @Override
+        protected boolean inSystemImage(int callerUid) {
+            return callerUid == SYSTEM_IMAGE_UID;
+        }
+
+        @Override
+        protected ServiceInfo<TestServiceType> parseServiceInfo(
+                ResolveInfo resolveInfo) throws XmlPullParserException, IOException {
+            int size = mServices.size();
+            for (int i = 0; i < size; i++) {
+                Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i);
+                ServiceInfo<TestServiceType> serviceInfo = map.get(resolveInfo);
+                if (serviceInfo != null) {
+                    return serviceInfo;
+                }
+            }
+            throw new IllegalArgumentException("Unexpected service " + resolveInfo);
+        }
+    }
+
+    static class TestSerializer implements XmlSerializerAndParser<TestServiceType> {
+
+        public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException {
+            out.attribute(null, "type", item.type);
+            out.attribute(null, "value", item.value);
+        }
+
+        public TestServiceType createFromXml(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            final String type = parser.getAttributeValue(null, "type");
+            final String value = parser.getAttributeValue(null, "value");
+            return new TestServiceType(type, value);
+        }
+    }
+
+    static class TestServiceType implements Parcelable {
+        final String type;
+        final String value;
+
+        public TestServiceType(String type, String value) {
+            this.type = type;
+            this.value = value;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            TestServiceType that = (TestServiceType) o;
+
+            return type.equals(that.type) && value.equals(that.value);
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * type.hashCode() + value.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return "TestServiceType{" +
+                    "type='" + type + '\'' +
+                    ", value='" + value + '\'' +
+                    '}';
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(type);
+            dest.writeString(value);
+        }
+
+        public TestServiceType(Parcel source) {
+            this(source.readString(), source.readString());
+        }
+
+        public static final Creator<TestServiceType> CREATOR = new Creator<TestServiceType>() {
+            public TestServiceType createFromParcel(Parcel source) {
+                return new TestServiceType(source);
+            }
+
+            public TestServiceType[] newArray(int size) {
+                return new TestServiceType[size];
+            }
+        };
+    }
+}
diff --git a/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java b/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java
new file mode 100644
index 0000000..59f780f
--- /dev/null
+++ b/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
+import android.os.Parcel;
+
+import java.net.InetAddress;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.junit.Assert.*;
+
+
+public class StaticIpConfigurationTest extends TestCase {
+
+    private static final String ADDRSTR = "192.0.2.2/25";
+    private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
+    private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
+    private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
+    private static final InetAddress DNS1 = IpAddress("8.8.8.8");
+    private static final InetAddress DNS2 = IpAddress("8.8.4.4");
+    private static final InetAddress DNS3 = IpAddress("4.2.2.2");
+    private static final String IFACE = "eth0";
+
+    private static InetAddress IpAddress(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+
+    private void checkEmpty(StaticIpConfiguration s) {
+        assertNull(s.ipAddress);
+        assertNull(s.gateway);
+        assertNull(s.domains);
+        assertEquals(0, s.dnsServers.size());
+    }
+
+    private boolean isEqual(StaticIpConfiguration s1, StaticIpConfiguration s2) {
+        return s1.equals(s2);
+    }
+
+    private void assertEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) {
+        assertTrue(isEqual(s1, s2));
+    }
+
+    private void assertNotEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) {
+        assertFalse(isEqual(s1, s2));
+    }
+
+    private StaticIpConfiguration makeTestObject() {
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        s.ipAddress = ADDR;
+        s.gateway = GATEWAY;
+        s.dnsServers.add(DNS1);
+        s.dnsServers.add(DNS2);
+        s.dnsServers.add(DNS3);
+        s.domains = "google.com";
+        return s;
+    }
+
+    @SmallTest
+    public void testConstructor() {
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        checkEmpty(s);
+    }
+
+    @SmallTest
+    public void testCopyAndClear() {
+        StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
+        checkEmpty(empty);
+
+        StaticIpConfiguration s1 = makeTestObject();
+        StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
+        assertEquals(s1, s2);
+        s2.clear();
+        assertEquals(empty, s2);
+    }
+
+    @SmallTest
+    public void testHashCodeAndEquals() {
+        HashSet<Integer> hashCodes = new HashSet();
+        hashCodes.add(0);
+
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        // Check that this hash code is nonzero and different from all the ones seen so far.
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.ipAddress = ADDR;
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.gateway = GATEWAY;
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS1);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS2);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS3);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.domains = "example.com";
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        assertFalse(s.equals(null));
+        assertEquals(s, s);
+
+        StaticIpConfiguration s2 = new StaticIpConfiguration(s);
+        assertEquals(s, s2);
+
+        s.ipAddress = new LinkAddress(DNS1, 32);
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.domains = "foo";
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.gateway = DNS2;
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.dnsServers.add(DNS3);
+        assertNotEquals(s, s2);
+    }
+
+    @SmallTest
+    public void testToLinkProperties() {
+        LinkProperties expected = new LinkProperties();
+        expected.setInterfaceName(IFACE);
+
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
+        s.ipAddress = ADDR;
+        expected.addLinkAddress(ADDR);
+        expected.addRoute(connectedRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = GATEWAY;
+        RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
+        expected.addRoute(defaultRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = OFFLINKGATEWAY;
+        expected.removeRoute(defaultRoute);
+        defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
+        expected.addRoute(defaultRoute);
+
+        RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
+        expected.addRoute(gatewayRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.dnsServers.add(DNS1);
+        expected.addDnsServer(DNS1);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.dnsServers.add(DNS2);
+        s.dnsServers.add(DNS3);
+        expected.addDnsServer(DNS2);
+        expected.addDnsServer(DNS3);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.domains = "google.com";
+        expected.setDomains("google.com");
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = null;
+        expected.removeRoute(defaultRoute);
+        expected.removeRoute(gatewayRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        // Without knowing the IP address, we don't have a directly-connected route, so we can't
+        // tell if the gateway is off-link or not and we don't add a host route. This isn't a real
+        // configuration, but we should at least not crash.
+        s.gateway = OFFLINKGATEWAY;
+        s.ipAddress = null;
+        expected.removeLinkAddress(ADDR);
+        expected.removeRoute(connectedRoute);
+        expected.addRoute(defaultRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+    }
+
+    private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
+        Parcel p = Parcel.obtain();
+        StaticIpConfiguration s2 = null;
+        try {
+            s.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            s2 = StaticIpConfiguration.CREATOR.createFromParcel(p);
+        } finally {
+            p.recycle();
+        }
+        assertNotNull(s2);
+        return s2;
+    }
+
+    @SmallTest
+    public void testParceling() {
+        StaticIpConfiguration s = makeTestObject();
+        StaticIpConfiguration s2 = passThroughParcel(s);
+        assertEquals(s, s2);
+    }
+}
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 0002ba7..7bf5f65 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -33,7 +33,8 @@
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-ifeq ($(LOCAL_USE_JACK),true)
+
+ifdef LOCAL_USE_JACK
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
 endif
 
@@ -41,10 +42,11 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/multidexlegacyandexception/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index c9dbb57..416c238 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-ifeq ($(LOCAL_USE_JACK),true)
+ifdef LOCAL_USE_JACK
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
 endif
 
@@ -41,12 +41,14 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/multidexlegacytestapp/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
+endif
 
 ## The application with a full main dex
 include $(CLEAR_VARS)
@@ -67,7 +69,7 @@
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-ifeq ($(LOCAL_USE_JACK),true)
+ifdef LOCAL_USE_JACK
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
 endif
 
@@ -75,9 +77,11 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList2): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/multidexlegacytestapp/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList2)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 16e396b..83ead4b 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -36,9 +36,10 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index c62238b..d706ca9 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -32,7 +32,8 @@
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-ifeq ($(LOCAL_USE_JACK),true)
+
+ifdef LOCAL_USE_JACK
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
 endif
 
@@ -40,9 +41,11 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index 8c0c5d5..99b2a8b 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -32,7 +32,8 @@
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-ifeq ($(LOCAL_USE_JACK),true)
+
+ifdef LOCAL_USE_JACK
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
 endif
 
@@ -40,9 +41,11 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 002c1cc..3ee1c22 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -32,7 +32,8 @@
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
-ifeq ($(LOCAL_USE_JACK),true)
+
+ifdef LOCAL_USE_JACK
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
 endif
 
@@ -40,10 +41,12 @@
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_USE_JACK
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
 	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
+endif
 
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index f94fe66..42b5d5d 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -335,11 +335,6 @@
     </family>
     <family>
         <fileset>
-            <file>NotoSansTaiLe-Regular.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
             <file>NotoSansTaiTham-Regular.ttf</file>
         </fileset>
     </family>
@@ -408,10 +403,13 @@
             <file lang="ja">MTLmr3m.ttf</file>
         </fileset>
     </family>
-    <!-- Note: complex scripts (i.e. those requiring shaping in Harfbuzz) have
-         a cumulative limit of 64k glyphs. Thus, if they are placed after the
-         large fonts such as DroidSansFallback, they are likely to render
-         incorrectly. Please use caution when putting fonts toward the end of
-         the list.
+    <!--
+        Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+        the East Asian punctuation for Chinese.
     -->
+    <family>
+        <fileset>
+            <file>NotoSansTaiLe-Regular.ttf</file>
+        </fileset>
+    </family>
 </familyset>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 02bf877..37527e9 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -288,9 +288,6 @@
         <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
     </family>
     <family>
-        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
-    </family>
-    <family>
         <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
     </family>
     <family>
@@ -332,4 +329,11 @@
     <family lang="ja">
         <font weight="400" style="normal">MTLmr3m.ttf</font>
     </family>
+    <!--
+        Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+        the East Asian punctuation for Chinese.
+    -->
+    <family>
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+    </family>
 </familyset>
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 5265f20..4e03108 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -57,7 +57,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 5, 2015.
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 2, 2015.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -88,7 +88,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 5, 2015.
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 2, 2015.
 
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
@@ -108,7 +108,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A69.9%2C30.1&chco=c4df9b%2C6fad0c&cht=p&chs=400x250" />
+src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A68.9%2C31.1&chco=c4df9b%2C6fad0c&cht=p&chs=400x250" />
 
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
@@ -127,17 +127,17 @@
 </tr>
 <tr>
 <td>2.0</td>
-<td>69.9%</td>
+<td>68.9%</td>
 </tr>
 <tr>
 <td>3.0</td>
-<td>30.1%</td>
+<td>31.1%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 5, 2015</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 2, 2015</em></p>
 
 
 
@@ -155,7 +155,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chco=c4df9b%2C6fad0c&chd=t%3A0.4%2C7.8%2C6.7%2C46.0%2C39.1&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat",
+    "chart": "//chart.googleapis.com/chart?chf=bg%2Cs%2C00000000&chd=t%3A0.4%2C7.4%2C6.4%2C44.5%2C39.7%2C1.6&chco=c4df9b%2C6fad0c&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop&chs=500x250&cht=p",
     "data": [
       {
         "api": 8,
@@ -165,32 +165,37 @@
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "7.8"
+        "perc": "7.4"
       },
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "6.7"
+        "perc": "6.4"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "19.2"
+        "perc": "18.4"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "20.3"
+        "perc": "19.8"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "6.5"
+        "perc": "6.3"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "39.1"
+        "perc": "39.7"
+      },
+      {
+        "api": 21,
+        "name": "Lollipop",
+        "perc": "1.6"
       }
     ]
   }
@@ -203,29 +208,29 @@
     "data": {
       "Large": {
         "hdpi": "0.6",
-        "ldpi": "0.6",
-        "mdpi": "5.4",
-        "tvdpi": "2.3",
+        "ldpi": "0.5",
+        "mdpi": "5.1",
+        "tvdpi": "2.2",
         "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "37.5",
-        "mdpi": "8.8",
+        "hdpi": "38.3",
+        "mdpi": "8.7",
         "tvdpi": "0.1",
-        "xhdpi": "18.4",
-        "xxhdpi": "16.3"
+        "xhdpi": "18.8",
+        "xxhdpi": "15.9"
       },
       "Small": {
         "ldpi": "4.8"
       },
       "Xlarge": {
         "hdpi": "0.3",
-        "mdpi": "3.7",
+        "mdpi": "3.5",
         "xhdpi": "0.6"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chd=t%3A5.4%2C17.9%2C2.4%2C38.4%2C19.6%2C16.3&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
-    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chd=t%3A4.6%2C9.5%2C81.1%2C4.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall"
+    "densitychart": "//chart.googleapis.com/chart?chf=bg%2Cs%2C00000000&chd=t%3A5.3%2C17.3%2C2.3%2C39.2%2C20.0%2C15.9&chco=c4df9b%2C6fad0c&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chs=400x250&cht=p",
+    "layoutchart": "//chart.googleapis.com/chart?chf=bg%2Cs%2C00000000&chd=t%3A4.4%2C9.0%2C81.8%2C4.8&chco=c4df9b%2C6fad0c&chl=Xlarge%7CLarge%7CNormal%7CSmall&chs=400x250&cht=p"
   }
 ];
 
@@ -305,7 +310,7 @@
   },
   {
     "api":21,
-    "link":"<a href='/about/versions/android-5.0.html'>4.4</a>",
+    "link":"<a href='/about/versions/android-5.0.html'>5.0</a>",
     "codename":"Lollipop"
   }
 ];
diff --git a/docs/html/about/versions/android-5.0-changes.jd b/docs/html/about/versions/android-5.0-changes.jd
index 3de5c3c..f51af40 100644
--- a/docs/html/about/versions/android-5.0-changes.jd
+++ b/docs/html/about/versions/android-5.0-changes.jd
@@ -24,13 +24,6 @@
   <li><a href="#managed_profiles">Support for Managed Profiles</a></li>
 </ol>
 
-<a class="notice-developers-video" href="https://www.youtube.com/watch?v=Uiq2kZ2JHVY">
-<div>
-    <h3>Video</h3>
-    <p>Notifications</p>
-</div>
-</a>
-
 <h2>API Differences</h2>
 <ol>
 <li><a href="{@docRoot}sdk/api_diff/21/changes.html">API level 20 to 21 &raquo;</a> </li>
@@ -48,6 +41,20 @@
 </div>
 </div>
 
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=um1S2u022HA">
+<div>
+    <h3>Video</h3>
+    <p>Dev Byte: What's New in Android 5.0</p>
+</div>
+</a>
+
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=Uiq2kZ2JHVY">
+<div>
+    <h3>Video</h3>
+    <p>Dev Byte: Notifications</p>
+</div>
+</a>
+
 <p>API Level: {@sdkPlatformApiLevel}</p>
 <p>Along with new features and capabilities, Android 5.0 includes a variety of
 system changes and API behavior changes. This document highlights
diff --git a/docs/html/google/gcm/adv.jd b/docs/html/google/gcm/adv.jd
deleted file mode 100644
index 95497e3..0000000
--- a/docs/html/google/gcm/adv.jd
+++ /dev/null
@@ -1,410 +0,0 @@
-page.title=GCM Advanced Topics
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<h2>Quickview</h2>
-
-<ul>
-<li>Learn more about GCM advanced features.</li>
-</ul>
-
-
-<h2>In this document</h2>
-
-<ol>
-<li><a href="#lifetime">Lifetime of a Message</a></li>
-<li><a href="#throttling">Throttling</a></li>
-<li><a href="#reg-state">Keeping the Registration State in Sync</a>
-  <ol>
-    <li><a href="#canonical">Canonical IDs</a></li>
-  </ol>
-</li>
-<li><a href="#retry">Automatic Retry Using Exponential Back-Off</a></li>
-<li><a href="#unreg">Unregistration</a>
-  <ol>
-    <li><a href="#unreg-why">Why you should rarely unregister</a></li>
-    <li><a href="#unreg-how">How unregistration works</a></li>
-  </ol>
-</li>
-<li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a>
-  <ol>
-    <li><a href="#s2s">Send-to-sync messages</a></li>
-    <li><a href="#payload">Messages with payload</a></li>
-<li><a href="#which">Which should I use?</a></li>
-    </ol>
-</li>
-<li><a href="#ttl">Setting an Expiration Date for a Message</a> </li>
-<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from
-Multiple Senders</a></li>
-</ol>
-
-</div>
-</div>
-<p>This document covers advanced topics for GCM.</p>
-
-
-
-
-<h2 id="msg-lifetime">Lifetime of a Message</h2>
-<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
-it does not mean that the message was already delivered to the device. Rather, it
-means that it was accepted for delivery. What happens to the message after it is
-accepted depends on many factors.</p>
-
-<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
-and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
-the message will be delivered right away.</p>
-
-<p>If the device is connected but idle, the message will still be
-delivered right away unless the <code>delay_while_idle</code> flag is set to true.
-Otherwise, it will be stored in the GCM servers until the device is awake. And
-that's where the <code>collapse_key</code> flag plays a role: if there is already
-a message with the same collapse key (and registration ID) stored and waiting for
-delivery, the old message will be discarded and the new message will take its place
-(that is, the old message will be collapsed by the new one). However, if the collapse
-key is not set, both the new and old messages are stored for future delivery.
-Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
-
-<p class="note"><strong>Note:</strong> There is a limit on how many messages can
-be stored without collapsing. That limit is currently 100. If the limit is reached,
-all stored messages are discarded. Then when the device is back online, it receives
-a special message indicating that the limit was reached. The application can then
-handle the situation properly, typically by requesting a full sync.
-<br><br>
-Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
-a particular device. GCM allows a maximum of 4 different collapse keys to be used
-by the GCM server per device
-any given time. In other words, the GCM server can simultaneously store 4 different
-send-to-sync messages, each with a different collapse key. If you exceed this number
-GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
-See <a href="#s2s">Send-to-sync messages</a> for more information.
-</p>
-
-<p>If the device is not connected to GCM, the message will be stored until a
-connection is established (again respecting the collapse key rules). When a connection
-is established, GCM will deliver all pending messages to the device, regardless of
-the <code>delay_while_idle</code> flag. If the device never gets connected again
-(for instance, if it was factory reset), the message will eventually time out and
-be discarded from GCM storage. The default timeout is 4 weeks, unless the
-<code>time_to_live</code> flag is set.</p>
-
-<p>Finally, when GCM attempts to deliver a message to the device and the
-application was uninstalled, GCM will discard that message right away and
-invalidate the registration ID. Future attempts to send a message to that device
-will get a <code>NotRegistered</code> error. See <a href="#unreg">
-How Unregistration Works</a> for more information.</p>
-<p>Although is not possible to track the status of each individual message, the
-Google Cloud Console stats are broken down by messages sent to device, messages
-collapsed, and messages waiting for delivery.</p>
-
-<h2 id="throttling">Throttling</h2>
-<p>To prevent abuse (such as sending a flood of messages to a device) and
-to optimize for the overall network efficiency and battery life of
-devices, GCM implements throttling of messages using a token bucket
-scheme. Messages are throttled on a per application and per <a href="#collapsible">collapse
-key</a> basis (including non-collapsible messages). Each application
-collapse key is granted some initial tokens, and new tokens are granted
-periodically therefter. Each token is valid for a single message sent to
-the device. If an application collapse key exhausts its supply of
-available tokens, new messages are buffered in a pending queue until
-new tokens become available at the time of the periodic grant. Thus
-throttling in between periodic grant intervals may add to the latency
-of message delivery for an application collapse key that sends a large
-number of messages within a short period of time. Messages in the pending
-queue of an application collapse key may be delivered before the time
-of the next periodic grant, if they are piggybacked with messages
-belonging to a non-throttled category by GCM for network and battery
-efficiency reasons.</p>
-
-<h2 id="reg-state">Keeping the Registration State in Sync</h2>
-<p>Whenever the application registers as described in
-<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
-it should save the registration ID for future use, pass it to the
-3rd-party server to complete the registration, and keep track of
-whether the server completed the registration. If the server fails
-to complete the registration, it should try again or unregister from GCM.</p>
-
-<p>There are also two other scenarios that require special care:</p>
-<ul>
-  <li>Application update</li>
-  <li>Backup and restore
-  </li>
-</ul>
-<p>When an application is updated, it should invalidate its existing registration
-ID, as it is not guaranteed to work with the new version.  Because there is no
-lifecycle method called when the application is updated, the best way to achieve
-this validation is by storing the current application version when a registration
-ID is stored. Then when the application is started, compare the stored value with
-the current application version. If they do not match, invalidate the stored data
-and start the registration process again.</p>
-
-<p>Similarly, you should not save the registration ID when an application is
-backed up. This is because the registration ID could become invalid by the time
-the application is restored, which would put the application in an invalid state
-(that is, the application thinks it is registered, but the server and GCM do not
-store that registration ID anymore&mdash;thus the application will not get more
-messages).</p>
-<h3 id="canonical">Canonical IDs</h3>
-<p>On the server side, as long as the application is behaving well, everything
-should work normally. However, if a bug in the application triggers multiple
-registrations for the same device, it can be hard to reconcile state and you might
-end up with duplicate messages.</p>
-<p>GCM provides a facility called &quot;canonical registration IDs&quot; to easily
-recover from these situations. A canonical registration ID is defined to be the ID
-of the last registration requested by your application. This is the ID that the
-server should use when sending messages to the device.</p>
-<p>If later on you try to send a message using a different registration ID, GCM
-will process the request as usual, but it will include the canonical registration
-ID in the <code>registration_id</code> field of the response. Make sure to replace
-the registration ID stored in your server with this canonical ID, as eventually
-the ID you're using will stop working.</p>
-
-<h2 id="retry">Automatic Retry Using Exponential Back-Off</h2>
-
-<p>When registration or unregistration fails, the app should retry the failed operation.</p>
-<p>In the simplest case, if your application attempts to register and GCM is not a
-fundamental part of the application, the application could simply ignore the error
-and try to register again the next time it starts. Otherwise, it should retry the
-previous operation using exponential back-off. In exponential back-off, each time
-there is a failure, it should wait twice the previous amount of time before trying
-again. If the register (or unregister) operation was synchronous, it could be retried
-in a simple loop. However, since it is asynchronous, the best approach is to schedule
-a {@link android.app.PendingIntent} to retry the operation.
-
-<h2 id="unreg">Unregistration</h2>
-
-<p>This section explains when you should unregister in GCM and what happens
-when you do.</p>
-
-<h3 id="unreg-why">Why you should rarely unregister</h3>
-
-<p>A registration ID (regID) represents a particular Android application running
-on a particular device. You should only need to unregister in rare cases, such as
-if you want an app to stop receiving messages, or if you suspect that the regID has
-been compromised. In general, though, once an app has a regID, you shouldn't need
-to change it.</p>
-
-<p>In particular, you should never unregister your app as a mechanism for
-logout or for switching between users, for the following reasons:</p>
-
-<ul>
-  <li>A regID maps an app to a device. It isn't associated with a particular
-  logged in user. If you unregister and then re-register, GCM may return the same
-  ID or a different ID&mdash;there's no guarantee either way.</li>
-
-  <li>Unregistration may take up to 5 minutes to propagate.</li>
-  <li>After unregistration, re-registration may again take up to 5 minutes to
-propagate. During this time messages may be rejected due to the state of being
-unregistered, and after all this, messages may still go to the wrong user.</li>
-</ul>
-
-
-<p>The solution is to manage your own mapping between users, the regID, and
-individual messages:</p>
-
-<ul>
-  <li>Your app server should maintain a mapping between the current user
-and the regID. This should include information about which user is supposed to
-receive a particular message.</li>
-  <li>The app running on the device should check to ensure that messages it
-receives match the logged in user.</li>
-</ul>
-
-
-<h3 id="unreg-how">How unregistration works</h3>
-
-<p>An application can be automatically unregistered after it is uninstalled from
-the device. However, this process does not happens right away, as Android does not
-provide an uninstall callback. What happens in this scenario is as follows:</p>
-<ol>
-  <li>The end user uninstalls the application.</li>
-  <li>The 3rd-party server sends a message to GCM server.</li>
-  <li>The GCM server sends the message to the device.</li>
-  <li>The GCM client receives the message and queries Package Manager about
-whether there are broadcast receivers configured to receive it, which returns
-<code>false</code>.
-</li>
-  <li>The GCM client informs the GCM server that the application was uninstalled.</li>
-  <li>The GCM server marks the registration ID for deletion.</li>
-  <li>The 3rd-party server sends a message to  GCM.</li>
-  <li>The GCM returns a <code>NotRegistered</code> error message to the 3rd-party server.</li>
-  <li>The 3rd-party deletes the registration ID.
-  </li>
-</ol>
-
-<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud
-Messaging framework present on the device.</p>
-
-<p>Note that it might take a while for the registration ID be completely removed
-from GCM. Thus it is possible that messages sent during step 7 above gets a valid
-message ID as response, even though the message will not be delivered to the device.
-Eventually, the registration ID will be removed and the server will get a
-<code>NotRegistered</code> error, without any further action being required from
-the 3rd-party server (this scenario happens frequently while an application is
-being developed and tested).</p>
-
-<h2 id="collapsible">Send-to-Sync  vs. Messages with Payload</h2>
-
-<p>Every message sent in GCM has the following characteristics:</p>
-<ul>
-  <li>It has a payload limit of 4096 bytes.</li>
-  <li>By default, it is stored by GCM for 4 weeks.</li>
-</ul>
-
-<p>But despite these similarities, messages can behave very differently depending
-on their particular settings. One major distinction between messages is whether
-they are collapsed (where each new message replaces the preceding message) or not
-collapsed (where each individual message is delivered). Every message sent in GCM
-is either a &quot;send-to-sync&quot; (collapsible) message or a &quot;message with
-payload&quot; (non-collapsible message). These concepts are described in more
-detail in the following sections.</p>
-
-<h3 id="s2s">Send-to-sync messages</h3>
-
-<p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells
-a mobile application to sync data from the server. For example, suppose you have
-an email application. When a user receives new email on the server, the server
-pings the mobile application with a &quot;New mail&quot; message. This tells the
-application to sync to the server to pick up the new email. The server might send
-this message multiple times as new mail continues to accumulate, before the application
-has had a chance to sync. But if the user has received 25 new emails, there's no
-need to preserve every &quot;New mail&quot; message. One is sufficient. Another
-example would be a sports application that updates users with the latest score.
-Only the most recent message is relevant, so it makes sense to have each new
-message replace the preceding message. </p>
-
-<p>The email and sports applications are cases where you would probably use the
-GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary
-string that is used to collapse a group of like messages when the device is offline,
-so that only the most recent message gets sent to the client. For example,
-&quot;New mail,&quot; &quot;Updates available,&quot; and so on</p>
-<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
-at any given time. In other words, the GCM server can simultaneously store 4
-different send-to-sync messages per device, each with a different collapse key.
-For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
-and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
-guarantees about which ones they will be.</p>
-
-<h3 id="payload">Messages with payload</h3>
-
-<p>Unlike a send-to-sync message, every &quot;message with payload&quot;
-(non-collapsible message) is delivered. The payload the message contains can be
-up to 4kb. For example, here is a JSON-formatted message in an IM application in
-which spectators are discussing a sporting event:</p>
-
-<pre class="prettyprint pretty-json">{
-  "registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
-  "data" : {
-    "Nick" : "Mario",
-    "Text" : "great match!",
-    "Room" : "PortugalVSDenmark",
-  },
-}</pre>
-
-<p>A &quot;message with payload&quot; is not simply a &quot;ping&quot; to the
-mobile application to contact the server to fetch data. In the aforementioned IM
-application, for example, you would want to deliver every message, because every
-message has different content. To specify a non-collapsible message, you simply
-omit the <code>collapse_key</code> parameter. Thus GCM will send each message
-individually. Note that the order of delivery is not guaranteed.</p>
-
-<p>GCM will store up to 100 non-collapsible messages. After that, all messages
-are discarded from GCM, and a new message is created that tells the client how
-far behind it is. The message is delivered through a regular
-<code>com.google.android.c2dm.intent.RECEIVE</code> intent with the
-extra <code>message_type</code>, for which the value is always the string
-&quot;deleted_messages&quot;.</p>
-
-<p>The application should respond by syncing with the server to recover the
-discarded messages. </p>
-
-<h3 id="which">Which should I use?</h3>
-  <p>If your application does not need to use non-collapsible messages, collapsible
-messages are a better choice from a performance standpoint, because they put less
-of a burden on the device battery. However, if you use collapsible messages, remember that
-<strong>GCM only allows a maximum of 4 different collapse keys to be used by the GCM server
-per device at any given time</strong>. You must not exceed this number, or it could cause
-unpredictable consequences.</p>
-
-<h2 dir="ltr" id="ttl">Setting an Expiration Date for a Message</h2>
-<p>The Time to Live (TTL) feature lets  the sender  specify the maximum lifespan
-of a message using the <code>time_to_live</code> parameter in the send request.
-The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
-it corresponds to the maximum period of time for which GCM will store and try to
-deliver the message. Requests that don't contain this field default to the maximum
-period of 4 weeks.</p>
-<p>Here are some possible uses for this feature:</p>
-<ul>
-  <li>Video chat incoming calls</li>
-  <li>Expiring invitation events</li>
-  <li>Calendar events</li>
-</ul>
-<h3 id="bg">Background </h3>
-<p>GCM will usually deliver messages immediately after they are sent. However,
-this might not always be possible. For example, the device could be turned off,
-offline, or otherwise unavailable. In other cases, the sender itself might request
-that messages not be delivered until the device becomes active by using the
-<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
-to prevent an application from consuming excessive resources and negatively
-impacting battery life.</p>
-
-<p>When this happens, GCM will store the message and deliver it as soon as it's
-feasible. While this is fine in most cases, there are some applications for which
-a late message might as well never be delivered. For example, if the message is
-an incoming call or video chat notification, it will only be meaningful for a
-small period of time before the call is terminated. Or if the message is an
-invitation to an event, it will be useless if received after the event has ended.</p>
-
-<p>Another advantage of specifying the expiration date for a message is that GCM
-will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
-In other words, GCM will guarantee best effort for messages that must be delivered
-&quot;now or never.&quot; Keep in mind that a <code>time_to_live</code> value of
-0 means messages that can't be delivered immediately will be discarded. However,
-because such messages are never stored, this provides the best latency for
-sending notifications.</p>
-
-<p>Here is an example of a JSON-formatted request that includes TTL:</p>
-<pre class="prettyprint pretty-json">
-{
-  "collapse_key" : "demo",
-  "delay_while_idle" : true,
-  "registration_ids" : ["xyz"],
-  "data" : {
-    "key1" : "value1",
-    "key2" : "value2",
-  },
-  "time_to_live" : 3
-},
-</pre>
-
-
-<h2 id="multi-senders">Receiving Messages from Multiple Senders</h2>
-
-<p>GCM allows multiple parties to send messages to the same application. For
-example, suppose your application is an articles aggregator with multiple
-contributors, and you want each of them to be able to send a message when they
-publish a new article. This message might contain a URL so that the application
-can download the article. Instead of having to centralize all sending activity in
-one location, GCM gives you the ability to let each of these contributors send
-its own messages.</p>
-
-<p>To make this possible, all you need to do is have each sender generate its own
-project number. Then include those IDs in the sender field, separated by commas,
-when requesting a registration. Finally, share the registration ID with your
-partners, and they'll be able to send messages to your application using their
-own authentication keys.</p>
-<p>This code snippet illustrates this feature. Senders are passed as an intent
-extra in a comma-separated list:</p>
-
-<pre class="prettyprint pretty-java">Intent intent = new Intent(GCMConstants.INTENT_TO_GCM_REGISTRATION);
-intent.setPackage(GSF_PACKAGE);
-intent.putExtra(GCMConstants.EXTRA_APPLICATION_PENDING_INTENT,
-        PendingIntent.getBroadcast(context, 0, new Intent(), 0));
-String senderIds = &quot;968350041068,652183961211&quot;;
-intent.putExtra(GCMConstants.EXTRA_SENDER, senderIds);
-ontext.startService(intent);
- </pre>
-
-<p>Note that there is limit of 100 multiple senders.</p>
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index 5c4a86e..fc95c2b 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -79,7 +79,7 @@
 
 <h3 id="interop">Relationship between C2DM and GCM</h3>
 
-<p>C2DM and GCM are not interoperable. For example, you cannot post notifications from GCM to C2DM registration IDs, nor can you use C2DM registration IDs as GCM registration IDs. From your server-side application, you must keep keep track of whether a registration ID is from C2DM or GCM and use the proper endpoint. </p>
+<p>C2DM and GCM are not interoperable. For example, you cannot post notifications from GCM to C2DM registration IDs, nor can you use C2DM registration IDs as GCM registration IDs. From your server-side application, you must keep track of whether a registration ID is from C2DM or GCM and use the proper endpoint. </p>
 
 <p>As you transition from C2DM to GCM, your server needs to be aware of whether a given registration ID
 contains an old C2DM sender or a new GCM project number. This is the approach we recommend: have the new app version (the one that uses GCM) send a bit along with the registration ID. This bit tells your server that this registration ID is for GCM. If you don't get the extra bit, you mark the registration ID as C2DM. Once no more valid registration IDs are marked as C2DM, you can complete the migration.</p>
@@ -87,13 +87,11 @@
 <h2 id="migrating">Migrating Your Apps</h2>
 <p>This section describes how to move existing C2DM apps to GCM.</p>
 <h3 id="client">Client changes</h3>
-<p>Migration is simple! The only change required in the application is replacing the email account passed in the sender parameter of the registration intent with the project number generated when signing up for the new service. For example:</p>
-<pre class="prettyprint pretty-java">Intent registrationIntent = new Intent(&quot;com.google.android.c2dm.intent.REGISTER&quot;);
-// sets the app name in the intent
-registrationIntent.putExtra(&quot;app&quot;, PendingIntent.getBroadcast(this, 0, new Intent(), 0));
-registrationIntent.putExtra(&quot;sender&quot;, senderID);
-startService(registrationIntent);</pre>
+<p>Migration is simple! Just re-register the client app for your target GCM-enabled platform. For
+  example, see <a href="{@docRoot}google/gcm/client.html#sample-register">Register for GCM</a></p>
+
 <p>After receiving a response from GCM, the registration ID obtained must be sent to the application server. When doing this, the application should indicate that it is sending a GCM registration ID so that the server can distinguish it from existing C2DM registrations.</p>
+
 <h3 id="server">Server changes</h3>
 <p>When the application server receives a GCM registration ID, it should store it and mark it as such.</p>
 <p>Sending messages to GCM devices requires a few changes:</p>
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 6332b8d..143b057 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -36,6 +36,7 @@
 <h2>See Also</h2>
 
 <ol class="toc">
+<li><a href="server-ref.html">Server Reference</a></li>
 <li><a href="{@docRoot}google/gcm/http.html">HTTP</a></li>
 <li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
 <li><a href="{@docRoot}google/gcm/server.html">Implementing GCM Server</a></li>
@@ -73,8 +74,8 @@
 APIs. For examples, see
 <a href="#implement">Implementing an XMPP-based App Server</a>.</p>
 
-<p class="note"><strong>Note:</strong> See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+<p class="note"><strong>Note:</strong> See the
+<a href="server-ref.html">Server Reference</a> for a list of all the message
 parameters and which connection server(s) supports them.</p>
 
 <h2 id="connecting">Establishing a Connection</h2>
@@ -176,8 +177,8 @@
 <a href="#flow">Flow Control</a> for details.
 </p>
 
-<p class="note"><strong>Note:</strong> See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+<p class="note"><strong>Note:</strong> See the
+<a href="server-ref.html">Server Reference</a> for a list of all the message
 parameters and which connection server(s) supports them.</p>
 
 <h3 id="request">Request format</h3>
@@ -278,56 +279,11 @@
 &lt;/message&gt;
 </pre>
 
-<p>The following table lists NACK error codes. Unless otherwise
+<p>See the <a href="server-ref.html#table11">Server Reference</a> for a complete list of the
+NACK error codes. Unless otherwise
 indicated, a NACKed message should not be retried. Unexpected NACK error codes
 should be treated the same as {@code INTERNAL_SERVER_ERROR}.</p>
 
-<p class="table-caption" id="table1">
-  <strong>Table 1.</strong> NACK error codes.</p>
-
-<table border="1">
-<tr>
-<th>Error Code</th>
-<th>Description</th>
-</tr>
-<tr>
-<td>{@code BAD_ACK}</td>
-<td>The ACK message is improperly formed.</td>
-</tr>
-<tr>
-<td>{@code BAD_REGISTRATION}</td>
-<td>The device has a registration ID, but it's invalid or expired.</td>
-</tr>
-<tr>
-<td>{@code CONNECTION_DRAINING}</td>
-<td>The message couldn't be processed because the connection is draining. The
-message should be immediately retried over another connection.</td>
-</tr>
-<tr>
-<td>{@code DEVICE_UNREGISTERED}</td>
-<td>The device is not registered.</td>
-</tr>
-<tr>
-<td>{@code INTERNAL_SERVER_ERROR}</td>
-<td>The server encountered an error while trying to process the request.</td>
-</tr>
-<tr>
-<td>{@code INVALID_JSON}</td>
-<td>The JSON message payload is not valid.</td>
-</tr>
-<td>{@code DEVICE_MESSAGE_RATE_EXCEEDED}</td>
-<td>The rate of messages to a particular device is too high. You should reduce
-the number of messages sent to this device and should not immediately retry
-sending to this device. This error code is replacing {@code QUOTA_EXCEEDED}.</td>
-</tr>
-<tr>
-  <td>{@code SERVICE_UNAVAILABLE}</td>
-  <td>CCS is not currently able to process the message. The
-    message should be retried over the same connection using exponential backoff
-    with an initial delay of 1 second.</td>
-</tr>
-</table>
-
 <h4 id="stanza">Stanza error</h4>
 
 <p>You can also get a stanza error in certain cases.
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index d44ee3c..9cb3f84 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -1,4 +1,4 @@
-page.title=Implementing GCM Client
+page.title=Implementing GCM Client on Android
 page.tags=cloud,push,messaging
 @jd:body
 
@@ -15,8 +15,8 @@
   <ol class="toc">
     <li><a href="#sample-play">Check for Google Play Services APK</a></li>
     <li><a href="#sample-register">Register for GCM</a></li>
-    <li><a href="#sample-send">Send a message</a></li>
-    <li><a href="#sample-receive">Receive a message</a></li>
+    <li><a href="#sample-receive">Receive a downstream message</a></li>
+    <li><a href="#sample-send">Send an upstream message</a></li>
   </ol>
   <li><a href="#run">Running the Sample</a></li>
   <li><a href="#stats">Viewing Statistics</a></li>
@@ -34,14 +34,26 @@
 </div>
 </div>
 
-<p>A Google Cloud Messaging (GCM) client is a GCM-enabled app that runs on an
+<p>A Google Cloud Messaging (GCM) Android client is a GCM-enabled app that runs on an
 Android device. To write your client code, we recommend that you use the
 <a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
-GCM APIs</a>.
-The client helper library that was offered in previous versions of GCM still works,
-but it has been superseded by the more efficient
-<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
-GCM APIs</a>.</p>
+{@code GoogleCloudMessaging}</a> API.</p>
+
+<p>Here are the requirements for running a GCM Android client:</p>
+
+<ul>
+  <li>At a bare minimum, GCM requires devices running Android 2.2 or higher that also have the
+Google Play Store application installed, or an emulator running Android 2.2
+with Google APIs. Note that you are not limited to deploying your
+Android applications through Google Play Store.</li>
+  <li>However, if you want to continue to use new GCM features that are distributed
+through Google Play Services, the device must be running Android 2.3 or higher, or
+you can use an emulator running Android 2.3 with Google APIs.</li>
+<li>On Android devices, GCM uses an existing connection for Google services. For
+pre-3.0 devices, this requires users to set up their Google accounts on their mobile
+devices. A Google account is not a requirement on devices running Android 4.0.4 or higher.</li>
+
+</ul>
 
 <p>A full GCM implementation requires both a client implementation and a server
 implementation. For more
@@ -58,7 +70,7 @@
 
 <p>To write your client application, use the
 <a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
-GCM APIs</a>.
+{@code GoogleCloudMessaging}</a> API.
 To use this API, you must set up your project to use the Google Play services SDK,
 as described in <a href="/google/play-services/setup.html">Setup Google Play
 Services SDK</a>.</p>
@@ -88,9 +100,6 @@
 the Android application can register and receive messages.</li>
   <li>The <code>android.permission.INTERNET</code> permission so the Android
 application can send the registration ID to the 3rd party server.</li>
-  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires
-a Google account (necessary only if if the device is running a version lower than
-Android 4.0.4)</li>
   <li>The <code>android.permission.WAKE_LOCK</code> permission so the application
 can keep the processor from sleeping when a message is received. Optional&mdash;use
 only if the app wants to keep the device from sleeping.</li>
@@ -101,7 +110,7 @@
    <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
 the category set
 as <code>applicationPackage</code>. The receiver should require the
-<code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
+<code>com.google.android.c2dm.permission.SEND</code> permission, so that only the GCM
 Framework can send a message to it. If your app uses an {@link android.app.IntentService}
 (not required, but a common pattern), this receiver should be an instance of
 {@link android.support.v4.content.WakefulBroadcastReceiver}.
@@ -324,8 +333,8 @@
         return "";
     }
     // Check if app was updated; if so, it must clear the registration ID
-    // since the existing regID is not guaranteed to work with the new
-    // app version.
+    // since the existing registration ID is not guaranteed to work with
+    // the new app version.
     int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
     int currentVersion = getAppVersion(context);
     if (registeredVersion != currentVersion) {
@@ -340,14 +349,14 @@
  */
 private SharedPreferences getGCMPreferences(Context context) {
     // This sample app persists the registration ID in shared preferences, but
-    // how you store the regID in your app is up to you.
+    // how you store the registration ID in your app is up to you.
     return getSharedPreferences(DemoActivity.class.getSimpleName(),
             Context.MODE_PRIVATE);
 }</pre>
 
 <p>If the registration ID doesn't exist or the app was updated,
 {@code getRegistrationId()} returns an empty string
-to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls
+to indicate that the app needs to get a new registration ID. {@code getRegistrationId()} calls
 the following method to check the app version:</p>
 
 <pre>/**
@@ -400,7 +409,7 @@
                 // will send upstream messages to a server that echo back the
                 // message using the 'from' address in the message.
 
-                // Persist the regID - no need to register again.
+                // Persist the registration ID - no need to register again.
                 storeRegistrationId(context, regid);
             } catch (IOException ex) {
                 msg = "Error :" + ex.getMessage();
@@ -433,7 +442,8 @@
 
 <p>After registering, the app calls {@code storeRegistrationId()} to store the
 registration ID in shared preferences for future use. This is just one way of
-persisting a regID. You might choose to use a different approach in your app:</p>
+persisting a registration ID. You might choose to use a different approach in
+your app:</p>
 
 <pre>/**
  * Stores the registration ID and app versionCode in the application's
@@ -455,64 +465,22 @@
 <h4 id="reg-errors">Handle registration errors</h4>
 
 <p>As stated above, an Android app must register with GCM servers and get a registration ID
-(regID) before it can receive messages. A given regID is not guaranteed to last indefinitely,
-so the first thing your app should always do is check to make sure it has a valid regID
-(as shown in the code snippets above).</p>
+before it can receive messages. A given registration ID is not guaranteed to last indefinitely,
+so the first thing your app should always do is check to make sure it has a valid
+registration ID (as shown in the code snippets above).</p>
 
-<p>In addition to confirming that it has a valid regID, your app should be prepared to handle
+<p>In addition to confirming that it has a valid registration ID, your app should be prepared to handle
 the registration error {@code TOO_MANY_REGISTRATIONS}. This error indicates that the device
 has too many apps registered with GCM. The error only occurs in cases where there are
 extreme numbers of apps, so it should not affect the average user. The remedy is to prompt
-the user to delete some of the other GCM-enabled apps from the device to make
+the user to delete some of the other client apps from the device to make
 room for the new one.</p>
 
-
-<h3 id="sample-send">Send a message</h3>
-<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
-upstream message using the
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
-your server should be connected to CCS. You can use one of the demo servers in
-<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
-to CCS.</p>
-
-<pre>public void onClick(final View view) {
-    if (view == findViewById(R.id.send)) {
-        new AsyncTask<Void, Void, String>() {
-            &#64;Override
-            protected String doInBackground(Void... params) {
-                String msg = "";
-                try {
-                    Bundle data = new Bundle();
-                        data.putString("my_message", "Hello World");
-                        data.putString("my_action",
-                                "com.google.android.gcm.demo.app.ECHO_NOW");
-                        String id = Integer.toString(msgId.incrementAndGet());
-                        gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
-                        msg = "Sent message";
-                } catch (IOException ex) {
-                    msg = "Error :" + ex.getMessage();
-                }
-                return msg;
-            }
-
-            &#64;Override
-            protected void onPostExecute(String msg) {
-                mDisplay.append(msg + "\n");
-            }
-        }.execute(null, null, null);
-    } else if (view == findViewById(R.id.clear)) {
-        mDisplay.setText("");
-    }
-}</pre>
-
-<h3 id="sample-receive">Receive a message</h3>
+<h3 id="sample-receive">Receive a downstream message</h3>
 
 <p>As described above in <a href="#manifest">Step 2</a>, the app includes a
 {@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
-intent. A broadcast receiver is the mechanism GCM uses to deliver messages. When {@code onClick()}
-calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()}
-method, which has the responsibility of making sure that the GCM message gets handled.</p>
+intent. A broadcast receiver is the mechanism GCM uses to deliver messages. </p>
 <p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
 broadcast receiver that takes care of
 creating and managing a
@@ -646,6 +614,46 @@
     }
 }</pre>
 
+
+<h3 id="sample-send">Send an upstream message</h3>
+<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
+upstream message using the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
+your server should be connected to CCS. You can use one of the demo servers in
+<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
+to CCS.</p>
+
+<pre>public void onClick(final View view) {
+    if (view == findViewById(R.id.send)) {
+        new AsyncTask<Void, Void, String>() {
+            &#64;Override
+            protected String doInBackground(Void... params) {
+                String msg = "";
+                try {
+                    Bundle data = new Bundle();
+                        data.putString("my_message", "Hello World");
+                        data.putString("my_action",
+                                "com.google.android.gcm.demo.app.ECHO_NOW");
+                        String id = Integer.toString(msgId.incrementAndGet());
+                        gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
+                        msg = "Sent message";
+                } catch (IOException ex) {
+                    msg = "Error :" + ex.getMessage();
+                }
+                return msg;
+            }
+
+            &#64;Override
+            protected void onPostExecute(String msg) {
+                mDisplay.append(msg + "\n");
+            }
+        }.execute(null, null, null);
+    } else if (view == findViewById(R.id.clear)) {
+        mDisplay.setText("");
+    }
+}</pre>
+
 <h2 id="run">Running the Sample</h2>
 
 <p>To run the sample:</p>
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 3d6594d..4e345b3 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -9,58 +9,24 @@
 <ol class="toc">
   <li><a href="#key">Key Concepts</a></li>
   <li><a href="#arch">Architectural Overview</a></li>
-  <li><a href="#lifecycle">Lifecycle Flow</a>
-    <ol class="toc">
-      <li><a href="#register">Enable GCM</a></li>
-      <li><a href="#push-process">Send a message</a></li>
-      <li><a href="#receiving">Receive a message</a></li>
-    </ol>
-  </li>
+  <li><a href="#lifecycle">Lifecycle Flow</a></li>
+  <li><a href="#reg">Register to enable GCM</a></li>
 </ol>
 
 </div>
 </div>
 
-<p>Google Cloud Messaging (GCM) for Android is a free service that helps
-developers  send data from servers to their Android applications on  Android
-devices, and upstream messages from the user's device back to the cloud.
-This could be a lightweight message telling the Android application
+<p>Google Cloud Messaging (GCM) is a free service that enables developers
+to send downstream messages (from servers to GCM-enabled client apps), and
+upstream messages (from the GCM-enabled client apps to servers).
+This could be a lightweight message telling the client app
 that there is new data to be fetched from the server (for instance, a "new email"
-notification informing the application that it is out of sync with the back end),
+notification informing the app that it is out of sync with the back end),
 or it could be a message containing up to 4kb of payload
 data (so apps like instant messaging can consume the message directly). The GCM
-service handles all aspects  of queueing of messages and delivery to the target
-Android application running  on the target device.</p>
-  
-<p class="note"> To jump right into using GCM with your Android
-  applications, see <a href="gs.html">Getting Started</a>.</p>
+service handles all aspects of queueing of messages and delivery to and from
+the target client app.</p>
 
-<p>Here are the primary characteristics of Google Cloud 
-Messaging (GCM):</p>
-
-<ul>
-  <li>It allows 3rd-party application servers to send messages to
-their Android applications.</li>
-  <li>Using the <a href="ccs.html">GCM Cloud Connection Server</a>, you can receive
-upstream messages from the user's device.</li>
-  <li>An Android application on an Android device doesn't need to be running to receive
-messages. The system will wake up the Android application via Intent broadcast
-when the  message arrives, as long as the application is set up with the proper
-broadcast receiver and permissions.</li>
-  <li>It does not provide any  built-in user interface or other handling for
-message data. GCM  simply passes raw message data received straight to the
-Android application,  which has full control of how to handle it. For example, the
-application might post a notification, display a custom user interface, or 
-silently sync data.</li>
-  <li>It requires devices running Android 2.2 or higher that also have the
-Google Play Store application installed, or or an emulator running Android 2.2
-with Google APIs. However, you are not limited to deploying your
-Android applications through Google Play Store.</li>
-  <li>It uses an existing connection for Google services. For pre-3.0 devices,
-this requires users to
-set up their Google account on their mobile devices. A Google account is not a
-requirement on devices running Android 4.0.4 or higher.</li>
-</ul>
 
 <h2 id="key">Key Concepts</h2>
 
@@ -70,7 +36,7 @@
   <li><strong>Components</strong> &mdash; The entities that play a primary role in
 GCM.</li>
   <li><strong>Credentials</strong> &mdash; The IDs and tokens that are used in
-different stages of GCM to ensure that all parties have been authenticated, and
+GCM to ensure that all parties have been authenticated, and
 that the message is going to the correct place.</li>
 </ul>
 
@@ -81,24 +47,20 @@
   <tr>
     <th colspan="2">Components</th>
   </tr>
-  <tr>
-    <td width="165"><strong>Client App</strong></td>
-    <td width="1176">The GCM-enabled Android application that is running on a
-    device. This must be a 2.2 Android device that has Google Play Store installed, and it must
-have at least one logged in Google account if the device is running a version
-lower than Android 4.0.4. Alternatively, for testing you can use an emulator
-running Android 2.2 with Google APIs.</td>
-  </tr>
-  <tr>
-    <td><strong>3rd-party Application Server</strong></td>
-    <td>An application server that you write as part of implementing
-GCM. The 3rd-party application server sends data to an
-Android application on the device via the GCM connection server.</td>
-  </tr>
-  <tr>
+<tr>
     <td><strong>GCM Connection Servers</strong></td>
-    <td>The Google-provided servers involved in taking messages from the 3rd-party
-application server and sending them to the device. </td>
+    <td>The Google-provided servers involved in sending messages between the
+3rd-party app server and the client app.</td>
+  </tr>
+  <tr>
+    <td><strong>Client App</strong></td>
+    <td>A GCM-enabled client app that communicates with a 3rd-party app server.</td>
+  </tr>
+  <tr>
+    <td><strong>3rd-party App Server</strong></td>
+    <td>An app server that you write as part of implementing
+GCM. The 3rd-party app server sends data to a client app via
+the GCM connection server.</td>
   </tr>
   <tr>
     <th colspan="2">Credentials</th>
@@ -108,42 +70,28 @@
     <td>A project number you acquire from the API console, as described in
 <a href="gs.html#create-proj">Getting Started</a>. The sender
 ID is used in the <a href="#register">registration process</a> to identify a
-3rd-party application server that is permitted to send messages to the device.</td>
-  </tr>
-  <tr>
-    <td><strong>Application ID</strong></td>
-    <td>The Android application that is registering to receive messages. The Android application
-is identified by the package name from the <a href="client.html#manifest">manifest</a>.
-This  ensures that the messages are targeted to the correct Android application.</td>
-  </tr>
-  <tr>
-    <td><strong>Registration ID</strong></td>
-    <td>An ID issued by the GCM servers to the Android application that allows
-it to receive messages. Once the Android application has the registration ID, it sends
-it to the 3rd-party application server, which uses it to identify each device 
-that has registered to receive messages for a given Android application. In other words,
-a registration ID is tied to a particular Android application running on a particular
-device. Note that registration IDs must be kept secret.
-<br/>
-<br/>
-<strong>Note:</strong> If you use 
-<a href="https://developer.android.com/google/backup/index.html">backup and restore</a>,
-you should explicitly avoid backing up registration IDs. When you back up
-a device, apps back up shared prefs indiscriminately. If you don't explicitly
-exclude the GCM registration ID, it could get reused on a new device,
-which would cause delivery errors.
-</td>
-  </tr>
-  <tr>
-    <td><strong>Google User Account</strong></td>
-    <td>For GCM to work, the mobile device must include at least one Google
-account if the device is running a version lower than Android 4.0.4.</td>
+3rd-party app server that is permitted to send messages to the client app.</td>
   </tr>
   <tr>
     <td id="apikey"><strong>Sender Auth Token</strong></td>
-    <td>An API key that is saved on the 3rd-party application
-server that gives the application server authorized access to Google services.
-The API key is included in the header of POST requests  that send messages.</td>
+    <td>An API key that is saved on the 3rd-party app
+server that gives the app server authorized access to Google services.
+The API key is included in the header of POST requests.
+</td>
+  </tr>
+  <tr>
+    <td><strong>Application ID</strong></td>
+    <td>The client app that is registering to receive messages. How this is implemented
+is platform-dependent. For example, an Android app
+is identified by the package name from the <a href="client.html#manifest">manifest</a>.
+This  ensures that the messages are targeted to the correct Android app.</td>
+  </tr>
+  <tr>
+    <td><strong>Registration ID</strong></td>
+    <td>An ID issued by the GCM servers to the client app that allows
+it to receive messages. Note that registration IDs must be kept secret.
+
+</td>
   </tr>
 
 </table>
@@ -152,7 +100,8 @@
 
 <p>A GCM implementation includes a Google-provided
 connection server, a 3rd-party app server that interacts with the connection
-server, and a GCM-enabled client app running on an Android device:</p>
+server, and a GCM-enabled client app. For example, this diagram shows GCM
+communicating with a client app on an Android device:</p>
 
 <img src="{@docRoot}images/gcm/GCM-arch.png">
 
@@ -163,84 +112,196 @@
 <p>This is how these components interact:</p>
 <ul>
   <li>Google-provided <strong>GCM Connection Servers</strong> take messages from
-a 3rd-party application server and send these messages to a
-GCM-enabled Android application (the &quot;client app&quot;) running on a device.
+a 3rd-party app server and send these messages to a
+GCM-enabled client app (the &quot;client app&quot;).
 Currently Google provides connection servers for <a href="http.html">HTTP</a>
 and <a href="ccs.html">XMPP</a>.</li>
-  <li>The <strong>3rd-Party Application Server</strong> is a component that you
+  <li>The <strong>3rd-Party App Server</strong> is a component that you
 implement to work with your chosen GCM connection server(s). App servers send
 messages to a GCM connection server; the connection server enqueues and stores the
-message, and then sends it to the device when the device is online.
+message, and then sends it to the client app.
 For more information, see <a href="server.html">Implementing GCM Server</a>.</li>
-  <li>The <strong>Client App</strong> is a GCM-enabled Android application running
-on a device. To receive GCM messages, this app must register with GCM and get a
+  <li>The <strong>Client App</strong> is a GCM-enabled client app.
+To receive GCM messages, this app must register with GCM and get a
 registration ID. If you are using the <a href="ccs.html">XMPP</a> (CCS) connection
-server, the client app can send "upstream" messages back to the connection server.
+server, the client app can send "upstream" messages back to the 3rd-party app server.
 For more information on how to implement the client app, see
-<a href="client.html">Implementing GCM Client</a>.</li>
+the documentation for your platform.</li>
 </ul>
 
 <h2 id="lifecycle">Lifecycle Flow</h2>
 
 <ul>
-  <li><a href="#register">Enable GCM</a>. An Android application running on a
-mobile device registers to receive messages.</li>
+  <li><strong>Register to enable GCM</strong>. A client app registers to receive messages.
+For more discussion, see <a href="#register">Register to enable GCM</a>.</li>
+  <li><strong>Send and receive downstream messages</strong>.
+  <ul>
+     <li>Send a message. A 3rd-party app server sends messages to the client app:
+       <ol>
+         <li>The 3rd-party app server <a href="server.html#send-msg">sends a message</a>
+to GCM connection servers.</li>
+         <li>The GCM connection server enqueues and stores the message if the device is offline.</li>
+         <li>When the device is online, the GCM connection server sends the message to the device. </li>
+         <li>On the device, the client app receives the message according to the platform-specific implementation.
+See your platform-specific documentation for details.</li>
+       </ol>
+    </li>
+  <li>Receive a message. A client app
+receives a message from a GCM server. See your platform-specific documentation for details
+on how a client app in that environment processes the messages it receives.</li>
+  </ul>
+</li>
 
-  <li><a href="#push-process">Send a message</a>. A 3rd-party application
-server sends messages to the device.</li>
-  <li><a href="#receiving">Receive a message</a>. An Android application
-receives a message from a GCM server.</li>
+  <li><strong>Send and receive upstream messages</strong>. This feature is only available if
+you're using the <a href="ccs.html">XMPP Cloud Connection Server</a> (CCS).
+<ul>
+     <li>Send a message. A client app sends messages to the 3rd-party app server:
+      <ol>
+        <li>On the device, the client app sends messages to XMPP (CCS).See your platform-specific
+          documentation for details on how a client app can send a message to XMPP (CCS).</li>
+        <li>XMPP (CCS) enqueues and stores the message if the server is disconnected.</li>
+        <li>When the 3rd-party app server is re-connected, XMPP (CCS) sends the message to the 3rd-party app server.</li>
+      </ol>
+    </li>
+  <li>Receive a message. A 3rd-party app server receives a message from XMPP (CCS) and then does the following:
+      <ol>
+        <li>Parses the message header to verify client app sender information.
+        <li>Sends "ack" to GCM XMPP connection server to acknowledge receiving the message.
+        <li>Optionally parses the message payload, as defined by the client app.
+      </ol>
+</li>
 </ul>
 
-<p>These processes are described in more detail below.</p>
+</li>
 
-<h3 id="register">Enable GCM</h3>
 
-<p>The first time the Android application needs to use the messaging service, it
-calls the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> method {@code register()}, as discussed in
-<a href="client.html">Implementing GCM Client</a>.
-The {@code register()} method returns a registration ID. The Android
-application should store this ID for later use (for instance,
-to check in <code>onCreate()</code> if it is already registered).
+</ul>
+
+<h2 id="reg">Register to enable GCM</h2>
+
+<p>Regardless of the platform you're developing on, the first step
+a client app must do is register with GCM. This section covers some of the general
+best practices for registration and unregistration. See your platform-specific docs for
+details on writing a GCM-enabled client app on that platform.</p>
+
+<h3 id="reg-state">Keeping the Registration State in Sync</h3>
+<p>Whenever the app registers as described in
+<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
+it should save the registration ID for future use, pass it to the
+3rd-party server to complete the registration, and keep track of
+whether the server completed the registration. If the server fails
+to complete the registration, the client app should retry passing the
+registration ID to 3rd-party app server to complete the registration.
+If this continues to fail, the client app should unregister from GCM.</p>
+
+<p>There are also two other scenarios that require special care:</p>
+<ul>
+  <li>Client app update</li>
+  <li>Backup and restore
+  </li>
+</ul>
+<p><bold>Client app update:</bold> When a client app is updated, it should invalidate its existing registration
+ID, as it is not guaranteed to work with the new version.  The recommended way to achieve
+this validation is by storing the current app version when a registration
+ID is stored. Then when the app starts, compare the stored value with
+the current app version. If they do not match, invalidate the stored data
+and start the registration process again.</p>
+
+<p><bold>Backup and restore: </bold> You should not save the registration ID when an app is
+backed up. This is because the registration ID could become invalid by the time
+the app is restored, which would put the app in an invalid state
+(that is, the app thinks it is registered, but the server and GCM do not
+store that registration ID anymore&mdash;thus the app will not get more
+messages). The best practice is to initiate the registration process as if the app has been
+installed for the first time.</p>
+
+<h4 id="canonical">Canonical IDs</h4>
+<p>If a bug in the app triggers multiple
+registrations for the same device, it can be hard to reconcile state and you might
+end up with duplicate messages.</p>
+<p>GCM provides a facility called &quot;canonical registration IDs&quot; to easily
+recover from these situations. A canonical registration ID is defined to be the ID
+of the last registration requested by your app. This is the ID that the
+server should use when sending messages to the device.</p>
+<p>If later on you try to send a message using a different registration ID, GCM
+will process the request as usual, but it will include the canonical registration
+ID in the <code>registration_id</code> field of the response. Make sure to replace
+the registration ID stored in your server with this canonical ID, as eventually
+the ID you're using will stop working.</p>
+
+<h3 id="retry">Automatic Retry Using Exponential Back-Off</h3>
+
+<p>When registration or unregistration fails, the app should retry the failed operation.</p>
+<p>In the simplest case, if your app attempts to register and GCM is not a
+fundamental part of the app, the app could simply ignore the error
+and try to register again the next time it starts. Otherwise, it should retry the
+previous operation using exponential back-off. In exponential back-off, each time
+there is a failure, it should wait twice the previous amount of time before trying
+again.
 </p>
 
-<h3 id="push-process">Send a message</h3>
+<h3 id="unreg">Unregistration</h3>
 
-<p>Here is the sequence of events that occurs when the application server sends a 
-message:</p>
+<p>This section explains when you should unregister in GCM and what happens
+when you do.</p>
 
+<h4 id="unreg-why">Why you should rarely unregister</h4>
+
+<p>You should only need to unregister in rare cases, such as
+if you want an app to stop receiving messages, or if you suspect that the registration ID has
+been compromised. In general, once an app has a registration ID, you shouldn't need
+to change it.</p>
+
+<p>In particular, you should never unregister your app as a mechanism for
+logout or for switching between users, for the following reasons:</p>
+
+<ul>
+  <li>A registration ID isn't associated with a particular
+  logged in user. If you unregister and then re-register, GCM may return the same
+  ID or a different ID&mdash;there's no guarantee either way.</li>
+
+  <li>Unregistration may take up to 5 minutes to propagate.</li>
+  <li>After unregistration, re-registration may again take up to 5 minutes to
+propagate. During this time messages may be rejected due to the state of being
+unregistered, and after all this, messages may still go to the wrong user.</li>
+</ul>
+
+
+<p>To make sure that messages go to the intended user:</p>
+
+<ul>
+  <li>Your app server can maintain a mapping between the current user
+and the registration ID.</li>
+  <li>The app can then check to ensure that messages it
+receives match the logged in user.</li>
+</ul>
+
+
+<h4 id="unreg-how">How unregistration works</h4>
+
+<p>An app can be automatically unregistered after it is uninstalled.
+However, this process does not happen right away. What happens in
+this scenario is as follows:</p>
 <ol>
-  <li>The application server sends a  message to  GCM servers.</li>
-  <li>Google enqueues and stores the message in case the device is
-offline.</li>
-  <li>When the device is online, Google sends the message to the device. </li>
-  <li>On the device, the system  broadcasts the  message to the specified
-Android application via Intent broadcast with proper permissions, so that only the
-targeted Android application gets the message. This wakes the Android application up. The
-Android application does not need to be running beforehand to receive the message.</li>
-  <li>The Android application processes the message. If the Android application is doing
-non-trivial processing, you may want to grab a
-{@link android.os.PowerManager.WakeLock} and do any processing in a service.</li>
+  <li>The end user uninstalls the client app.</li>
+  <li>The 3rd-party app server sends a message to GCM server.</li>
+  <li>The GCM server sends the message to the GCM client on the device.</li>
+  <li>The GCM client on the device receives the message and detects that the client app has been
+   uninstalled; the detection details depend on the platform on which the client app is running.
+</li>
+  <li>The GCM client on the device informs the GCM server that the client app was uninstalled.</li>
+  <li>The GCM server marks the registration ID for deletion.</li>
+  <li>The 3rd-party app server sends a message to  GCM.</li>
+  <li>The GCM returns a <code>NotRegistered</code> error message to the 3rd-party app server.</li>
+  <li>The 3rd-party app server deletes the registration ID.
+  </li>
 </ol>
 
-<p> An Android application can  unregister GCM if it no longer wants to receive 
-messages.</p>
-
-<h3 id="receiving">Receive a message</h3>
-
-<p>This is the sequence of events that occurs when an Android application
-installed on a mobile device receives a message:</p>
-
-<ol>
-  <li>The system receives the incoming message and extracts the raw key/value
-pairs from the message payload, if any.</li>
-  <li>The system passes the key/value pairs to the targeted Android application
-in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
-extras.</li>
-  <li>The Android application extracts the raw data
-from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
-by key and processes the data.</li>
-</ol>
-
+<p>Note that it might take a while for the registration ID be completely removed
+from GCM. Thus it is possible that messages sent during step 7 above gets a valid
+message ID as response, even though the message will not be delivered to the client app.
+Eventually, the registration ID will be removed and the server will get a
+<code>NotRegistered</code> error, without any further action being required from
+the 3rd-party server (this scenario happens frequently while an app is
+being developed and tested).</p>
 
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index a889624..2331292 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -1,4 +1,4 @@
-page.title=Getting Started
+page.title=Getting Started on Android
 page.tags=cloud,push,messaging
 @jd:body
 
@@ -46,7 +46,7 @@
 
   <li>Copy down your project number. You will use it later on as the
   <a href="{@docRoot}google/gcm/gcm.html#senderid">GCM sender ID</a>.</li>
-  
+
 </ol>
 <h2 id="gcm-service">Enabling the GCM Service</h2>
 <p>To enable the GCM service:</p>
@@ -71,7 +71,7 @@
 
 <li>In the refreshed page, copy the
 <a href="{@docRoot}google/gcm/gcm.html#apikey">API key</a>.
-You will need the API key later on to perform authentication in your application server.</li>
+You will need the API key later on to perform authentication in your app server.</li>
 
 <p class="note"><strong>Note:</strong> If you need to rotate the key, click
 <strong>Regenerate key</strong>. A new key  will be created. If you think the key has been
@@ -84,16 +84,11 @@
 implementing GCM. Here is an overview of the basic steps:</p>
 
 <ol>
-  <li>Decide which Google-provided GCM connection server you want to use&mdash;
-  <a href="http.html">HTTP</a> or <a href="ccs.html">XMPP</a> (CCS). GCM connection servers
-take messages from a 3rd-party application
-server (written by you) and send them to a GCM-enabled Android application (the
-"client app," also written by you) running on a device. </li>
-  <li>Implement an application server (the "3rd-party application server") to interact
+  <li>Implement an app server (the "3rd-party app server") to interact
 with your chosen GCM connection server. The app server sends data to a
-GCM-enabled Android client application via the GCM connection server. For more
+GCM-enabled Android client app via the GCM connection server. For more
 information about implementing the server side, see <a href="server.html">
 Implementing GCM Server</a>.</li>
-<li>Write your client app. This is the GCM-enabled Android application that runs
+<li>Write your client app. This is the GCM-enabled Android app that runs
 on a device. See <a href="client.html">Implementing GCM Client</a> for more information.</li>
 </ol>
diff --git a/docs/html/google/gcm/http.jd b/docs/html/google/gcm/http.jd
index 773acd1..5022e09 100644
--- a/docs/html/google/gcm/http.jd
+++ b/docs/html/google/gcm/http.jd
@@ -23,6 +23,7 @@
 <h2>See Also</h2>
 
 <ol class="toc">
+<li><a href="server-ref.html">Server Reference</a></li>
 <li><a href="gs.html">Getting Started</a></li>
 <li><a href="client.html">Implementing GCM Client</a></li>
 <li><a href="ccs.html">Cloud Connection Server</a></li>
@@ -42,26 +43,30 @@
 applies to <a href="http://developer.chrome.com/apps/cloudMessaging">
 GCM with Chrome apps</a> as well as Android.</p>
 
-<p>See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+<p>See the
+<a href="server-ref.html">Server Reference</a> for a list of all the message
 parameters and which connection server(s) supports them.</p>
 
 
 <h2 id="auth">Authentication</h2>
 
-<p>To send a  message, the application server issues a POST request to
-<code>https://android.googleapis.com/gcm/send</code>.</p>
+<p>To send a  message, the application server issues a POST request. For example:</p>
+<pre>https://android.googleapis.com/gcm/send</pre>
 <p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
 
 <p>The HTTP header must contain the following headers:</p>
 <ul>
   <li><code>Authorization</code>: key=YOUR_API_KEY</li>
-  <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
+  <li><code>Content-Type</code>: <code>application/json</code> for JSON;
+<code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
+If <code>Content-Type</code> is omitted, the format
+is assumed to be plain text.
   </li>
 </ul>
 
 <p>For example:
 </p>
+
 <pre>Content-Type:application/json
 Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
 
@@ -71,26 +76,30 @@
     ...
   },
 }</pre>
-<p class="note">
-  <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format
-is assumed to be plain text.</p>
-</p>
+
 
 <p>The HTTP body content depends on whether you're using JSON or plain text.
 See
-<a href="server.html#params">Implementing GCM Server</a> for a list of all the
+<a href="server-ref.html#params">the Server Reference</a> for a list of all the
 parameters your JSON or plain text message can contain.</p>
 
 
   <h2 id="request">Request Format</h2>
+
+<p>This section shows you how to format a request for both JSON and plain text. See
+the <a href="server-ref.html#table1">Server Reference</a> for a complete
+list of the fields you can include in a request.</p>
+
   <p>Here is the smallest possible request (a message without any parameters and
 just one recipient) using JSON:</p>
+
   <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
 
   <p>And here the same example using plain text:</p>
   <pre class="prettyprint">registration_id=42</pre>
 
   <p> Here is a message with a payload and 6 recipients:</p>
+
   <pre class="prettyprint pretty-HTML">{ "data": {
     "score": "5x1",
     "time": "15:10"
@@ -112,10 +121,25 @@
   <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
   </pre>
 
+<p>Here is a message that includes a notification key and payload:</p>
+
+<pre>
+{
+  "data": {
+    "message": "ciao"
+  },
+  "notification_key":"aUniqueKey"
+}
+</pre>
+
+<p>For more information about notifications and how to use them, see
+<a href="{@docRoot}google/gcm/notifications.html">User Notifications</a>.</p>
+
+
 <p class="note"><strong>Note:</strong> If your organization has a firewall
 that restricts the traffic to or
 from the Internet, you need to configure it to allow connectivity with GCM in order for
-your Android devices to receive messages.
+your GCM client apps to receive messages.
 The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
 it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
 your firewall to accept outgoing connections to all IP addresses
@@ -127,54 +151,12 @@
 
 <p>There are two possible outcomes when trying to send a message:</p>
 <ul>
-  <li>The message is processed successfully.</li>
-  <li>The GCM server rejects the request.</li>
+  <li>The message is processed successfully. The HTTP response has a 200 status, and
+the body contains more information about the status of the message (including possible errors).</li>
+  <li>The GCM server rejects the request. The HTTP response contains a
+non-200 status code (such as 400, 401 or 5xx).</li>
 </ul>
 
-<p>When the message is processed successfully, the HTTP response has a 200 status
-and the body contains more information about the status of the message
-(including possible errors). When the request is rejected,
-the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
-
-<p>The following table summarizes the statuses that the HTTP response header might
-contain. Click the troubleshoot link for advice on how to deal with each type of
-error.</p>
-<table border=1>
-  <tr>
-    <th>Response</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td>200</td>
-    <td>Message was processed successfully. The response body will contain more
-details about the message status, but its format will depend whether the request
-was JSON or plain text. See <a href="#success">Interpreting a success response</a>
-for more details.</td>
-  </tr>
-  <tr>
-    <td>400</td>
-    <td><span id="internal-source-marker_0.2">Only applies for JSON requests.
-Indicates that the request could not be parsed as JSON, or it contained invalid
-fields (for instance, passing a string where a number was expected). The exact
-failure reason is described in the response and the problem should be addressed
-before the request can be retried.</td>
-  </tr>
-  <tr>
-    <td>401</td>
-    <td>There was an error authenticating the sender account.
-<a href="#auth_error">Troubleshoot</a></td>
-  </tr>
-  <tr>
-    <td>5xx</td>
-    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was
-an internal error in the GCM server while trying to process the request, or that
-the server is temporarily unavailable (for example, because of timeouts). Sender
-must retry later, honoring any <code>Retry-After</code> header included in the
-response. Application servers must implement exponential back-off.
-<a href="#internal_error">Troubleshoot</a></td>
-  </tr>
-</table>
-
 <h3 id="success">Interpreting a success response</h3>
 <p>When a JSON request is successful (HTTP status code 200), the response body
 contains a JSON object with the following fields:</p>
@@ -241,8 +223,8 @@
 request.</li>
       <li>If it is <code>NotRegistered</code>, you should remove the registration
 ID from your server database because the application was uninstalled from the
-device or it does not have a broadcast receiver configured to receive
-<code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
+device, or the client app isn't configured to receive
+messages.</li>
       <li>Otherwise, there is something wrong in the registration ID passed in
 the request; it is probably a non-recoverable error that will also require removing
 the registration from the server database. See <a href="#error_codes">Interpreting
@@ -291,8 +273,7 @@
 
 <dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
 <dd>Check the formatting of the registration ID that you pass to the server. Make
-sure it matches the registration ID the phone receives in the
-<code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're
+sure it matches the registration ID the client app receives and that you're
 not truncating it or adding additional characters.
 <br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
 
@@ -306,17 +287,13 @@
 <dt id="unreg_device"><strong>Unregistered Device</strong></dt>
 <dd>An existing registration ID may cease to be valid in a number of scenarios, including:
 <ul>
-  <li>If the application manually unregisters by issuing a
-<span class="prettyprint pretty-java">
-<code>com.google.android.c2dm.intent.UNREGISTER</code></span><code>
-</code>intent.</li>
+  <li>If the application manually unregisters.</li>
   <li>If the application is automatically unregistered, which can happen
 (but is not guaranteed) if the user uninstalls the application.</li>
   <li>If the registration ID expires. Google might decide to refresh registration
 IDs. </li>
-  <li>If the application is updated but the new version does not have a broadcast
-receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code>
-intents.</li>
+  <li>If the application is updated but the new version is not configured to receive
+messages.</li>
 </ul>
 For all these cases, you should remove this registration ID from the 3rd-party
 server and stop using it to send
@@ -331,8 +308,7 @@
 
 <dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
 <dd>The payload data contains a key (such as <code>from</code> or any value
-prefixed by <code>google.</code>) that is used internally by GCM in the
-<code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used.
+prefixed by <code>google.</code>) that is used internally by GCM and therefore cannot be used.
 Note that some words (such as <code>collapse_key</code>) are also used by GCM
 but are allowed in the payload, in which case the payload value will be
 overridden by the GCM value.
@@ -354,9 +330,9 @@
 <li>Request originated from a server not whitelisted in the Server Key IPs.</li>
 
 </ul>
-Check that the token you're sending inside the <code>Authorization</code> header
-is the correct API key associated with your project. You can check the validity
-of your API key by running the following command:<br/>
+When there is an Authentication Error, you can check the validity of your API key by running You can check the validity
+of your API key by running the following command (this example shows what you
+would do on Android; see the documentation for your platform):<br/>
 
 <pre># api_key=YOUR_API_KEY
 
@@ -405,8 +381,7 @@
 <dd>
 The server encountered an error while trying to process the request. You
 could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
-section), but if the error persists, please report the problem in the
-<a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
+section), but if the error persists, please report the problem to Google.
 <br />
 Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
 object in the results array is <code>InternalServerError</code>.
@@ -488,7 +463,7 @@
 
 <p>This section gives examples of implementing an app server that works with the
 GCM HTTP connection server. Note that a full GCM implementation requires a
-client-side implementation, in addition to the server.</a>
+client-side implementation, in addition to the server. This example is based on Android.</a>
 
 
 <p>Requirements</p>
@@ -508,7 +483,7 @@
 </ul>
 <p>For the Android application:</p>
 <ul>
-  <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
+  <li>Emulator (or device) running Android 2.2 (ideally, 2.3 or above) with Google APIs.</li>
   <li>The Google API project number of the account registered to use GCM.</li>
 </ul>
 
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index 147b69c..333d4b6 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -306,9 +306,3 @@
 <p>In the case of failure, the response has HTTP code 503 and no JSON. When a message
 fails to be delivered to one or more of the regIDs associated with a {@code notification_key},
 the 3rd-party server should retry.</p>
-
-
-
-
-
-
diff --git a/docs/html/google/gcm/server-ref.jd b/docs/html/google/gcm/server-ref.jd
new file mode 100644
index 0000000..a94e727
--- /dev/null
+++ b/docs/html/google/gcm/server-ref.jd
@@ -0,0 +1,763 @@
+page.title=Server Reference
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+<ol class="toc">
+  <li><a href="#downstream">Downstream Messages</a></li>
+<ol class="toc">
+      <li><a href="#send-downstream">Sending a downstream message</a></li>
+      <li><a href="#interpret-downstream">Interpreting a downstream message response</a></li>
+    </ol>
+  <li><a href="#upstream">Upstream Messages (XMPP)</a>
+    <ol class="toc">
+      <li><a href="#interpret-upstream">Interpreting an upstream XMPP message</a></li>
+      <li><a href="#upstream-response">Sending an upstream XMPP message response</a></li>
+    </ol>
+  </li>
+<li><a href="#ccs">Cloud Connection Server Messages (XMPP)</a></li>
+<li><a href="#error-codes">Downstream message error response codes (HTTP and XMPP)</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>This document provides a reference for the syntax used to pass
+messages back and forth in GCM. These messages fall into
+the following broad categories:</p>
+
+<ul>
+   <li><a href="#downstream">Downstream messages</a></li>
+   <li><a href="#upstream">Upstream messages</a></li>
+   <li><a href="#ccs">Cloud Connection Server messages (XMPP)</a></li>
+   <li><a href="#error-codes">Downstream message error response codes (HTTP and XMPP)</a></li>
+</ul>
+
+<p>The following sections describe the basic requirements for
+sending messages.</p>
+
+<h2 id="downstream">Downstream Messages</h2>
+<p>This is the message that a 3rd-party app server sends to a client app.
+</p>
+<p>A downstream message includes the following components:</p>
+<ul>
+  <li>Target: specifies the recipient of the message.</li>
+  <li>Options: specifies attributes of the message.</li>
+  <li>Payload: specifies additional content to be included in the message. Optional.</li>
+</ul>
+
+<p>The syntax for each of these components is described in the tables below. </p>
+
+<h3 id="send-downstream">Sending a downstream message</h3>
+
+<p>This section gives the syntax for sending a downstream messages. For JSON,
+these messages can be either HTTP or XMPP. For plain text, these messages can only be HTTP.</p>
+
+<h4>Downstream HTTP or XMPP messages (JSON)</h4>
+
+<p>The following table lists the targets, options, and payload for HTTP or XMPP JSON messages.</p>
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> Targets, options, and payload for downstream HTTP or XMPP message (JSON).</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Protocol</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+<tr>
+    <td colspan="4"><strong>Targets</strong></td>
+  </tr>
+  <tr>
+    <td><code>to</code></td>
+    <td>XMPP</td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies the recipient of a message. </p>
+      <p>The value must be a registration ID or notification key.</p>
+    <p>This parameter is used in XMPP in place of {@code registration_ids} or   {@code notification_key} in HTTP.</p></td>
+  </tr>
+  <tr>
+    <td><code>registration_ids</code></td>
+    <td>HTTP</td>
+    <td>Required if {@code notification_key} not present, string array</td>
+    <td><p>This parameter specifies the list of devices (registration IDs)
+receiving the message. It must contain at least 1 and at most 1000 registration IDs.</p>
+      <p>Multicast messages (sending to more than 1 registration IDs) are allowed using HTTP JSON format only.</p>
+    <p>This parameter or {@code notification_key} is used in HTTP in place of {@code to} in XMPP.</p></td>
+  </tr>
+  <tr>
+    <td><code>notification_key</code></td>
+    <td>HTTP</td>
+    <td>Required if {@code registration_ids} not present, string</td>
+    <td><p>This parameter specifies the mapping of a single user to
+multiple registration IDs associated with that user.</p>
+      <p>This allows a 3rd-party app server to send a single message to multiple app instances
+(typically on multiple devices) owned by a single user.</p>
+      <p>A 3rd-party app server can use {@code notification_key} as the target for a
+message instead of an individual registration ID (or array of registration IDs).
+The maximum number of members allowed for a {@code notification_key} is 20.</p>
+      <p>This parameter or {@code registration_ids} is used in HTTP in place of {@code to} in XMPP.</p>
+    <p>See <a href="notifications.html">User Notifications</a> for details.</p></td>
+  </tr>
+<tr>
+    <td colspan="4"><strong>Options</strong></td>
+  </tr>
+  <tr>
+    <td><code>message_id</code></td>
+    <td>XMPP</td>
+    <td>Required, string</td>
+    <td><p>This parameter uniquely identifies a message in an XMPP connection.</p></td>
+  </tr>
+  <tr>
+    <td><code>collapse_key</code></td>
+    <td>HTTP, XMPP</td>
+    <td>Optional, string</td>
+    <td><p>This parameters identifies a group of messages (e.g., with
+{@code collapse_key: "Updates Available"}) that can be collapsed, so that only the
+last message gets sent when delivery can be resumed. This is intended to avoid sending too
+many of the same messages when the device comes back online or becomes active (see {@code delay_while_idle}).</p>
+      <p>Note that there is no guarantee of the order in which messages get sent.</p>
+      <p>Messages with collapse key are also called
+<a href="{@docRoot}google/gcm/server.html#s2s">send-to-sync messages</a> messages.
+</p>
+    <p>Note: A maximum of 4 different collapse keys is allowed at any given time. This means a
+GCM connection server can simultaneously store 4 different send-to-sync messages per client app. If you
+exceed this number, there is no guarantee which 4 collapse keys the GCM connection server will keep. </p></td>
+  </tr>
+  <tr>
+    <td><code>delay_while_idle</code></td>
+    <td>HTTP, XMPP</td>
+    <td>Optional, JSON boolean</td>
+    <td>When this parameter is set to {@code true}, it indicates that the message should not be
+sent until the device becomes active.</p>
+    <p>The default value is {@code false}.</p></td>
+  </tr>
+  <tr>
+    <td><code>time_to_live</code></td>
+    <td>HTTP, XMPP</td>
+    <td>Optional, JSON number</td>
+    <td><p>This parameter specifies how long (in seconds) the message should be kept in GCM storage
+if the device is offline. The maximum time to live supported is 4 weeks.</p>
+    <p>The default value is 4 weeks. </p></td>
+  </tr>
+  <tr>
+    <td><code>delivery_receipt_
+<br>requested</code></td>
+    <td>XMPP</td>
+    <td>Optional, JSON boolean</td>
+    <td><p>This parameter lets 3rd-party app server request confirmation of message delivery.</p>
+      <p>When this parameter is set to {@code true}, CCS sends a delivery receipt
+when the device confirms that it received the message.</p>
+    <p>The default value is {@code false}.</p></td>
+  </tr>
+  <tr>
+    <td><code>restricted_package_
+<br>name</code></td>
+    <td>HTTP</td>
+    <td>Optional, string</td>
+    <td>This parameter specifies the package name of the application where the
+registration IDs must match in order to receive the message.</td>
+  </tr>
+  <tr>
+    <td><code>dry_run</code></td>
+    <td>HTTP</td>
+    <td>Optional, JSON boolean</td>
+    <td><p>This parameter, when set to {@code true}, allows developers to test a
+request without actually sending a message.</p>
+    <p>The default value is {@code false}.</p></td>
+  </tr>
+<tr>
+    <td colspan="4"><strong>Payload</strong></td>
+  </tr>
+  <tr>
+    <td><code>data</code></td>
+    <td>HTTP, XMPP</td>
+    <td>Optional, JSON object</td>
+    <td><p>This parameter specifies the key-value pairs of the message's payload. There is
+no limit on the number of key-value pairs, but there is a total message size limit of 4kb.</p>
+      <p>For instance, in Android, <code>data:{"score":"3x1"}</code> would result in an intent extra
+named {@code score} with the string value {@code 3x1}.</p>
+      <p>The key should not be a reserved word ({@code from} or any word starting with
+{@code google}). It is also not recommended to use words defined in this table
+(such as {@code collapse_key}) because that could yield unpredictable outcomes. </p>
+    <p>Values in string types are recommended. You have to convert values in objects
+or other non-string data types (e.g., integers or booleans) to string.</p></td>
+  </tr>
+</table>
+
+<h3>Downstream HTTP messages (Plain Text)</h3>
+
+<p>The following table lists the syntax for targets, options, and payload in plain
+text downstream HTTP messages.</p>
+
+<p class="table-caption" id="table2">
+  <strong>Table 2.</strong> Targets, options, and payload for downstream plain text HTTP messages.</p>
+
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+<tr>
+    <td colspan="3"><strong>Targets</strong></td>
+  </tr>
+  <tr>
+    <td><code>registration _id</code></td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies the client apps (registration ID) receiving the message.</p>
+    <p>Multicast messaging (sending to more than one registration ID) is allowed using HTTP JSON format only.</p></td>
+  </tr>
+<tr>
+    <td colspan="3"><strong>Options</strong></td>
+  </tr>
+  <tr>
+    <td><code>collapse_key</code></td>
+    <td>Optional, string</td>
+    <td>See <a href="#table1">table 1</a> for details.</td>
+  </tr>
+  <tr>
+    <td><code>delay_while_idle</code></td>
+    <td>Optional, boolean or number</td>
+    <td>See <a href="#table1">table 1</a> for details.</td>
+  </tr>
+  <tr>
+    <td><code>time_to_live</code></td>
+    <td>Optional, number</td>
+    <td>See <a href="#table1">table 1</a> for details.</td>
+  </tr>
+  <tr>
+    <td><code>restricted_package_name</code></td>
+    <td>Optional, string</td>
+    <td>See <a href="#table1">table 1</a> for details.</td>
+  </tr>
+  <tr>
+    <td><code>dry_run </code></td>
+    <td>Optional, boolean</td>
+    <td>See <a href="#table1">table 1</a> for details.</td>
+  </tr>
+<tr>
+    <td colspan="3"><strong>Payload</strong></td>
+  </tr>
+  <tr>
+    <td><code>data.&lt;key&gt;</code></td>
+    <td>Optional, string</td>
+    <td><p>This parameter specifies the key-value pairs of the message's payload.
+There is no limit on the number of key-value parameters,
+but there is a total message size limit of 4kb.</p>
+      <p>For instance, in Android, <code>data:{"score":"3x1"}</code> would result in an intent extra
+named {@code score} with the string value {@code 3x1}.</p>
+    <p>The key should not be a reserved word ({@code from} or any word starting with
+{@code google}). It is also not recommended to use words defined in this table
+(such as {@code collapse_key}) because that could yield unpredictable outcomes.</p></td>
+  </tr>
+</table>
+
+<h3 id="interpret-downstream">Interpreting a Downstream Message Response</h3>
+
+<p>This section describes the syntax of a response to a downstream message. A client
+app or the GCM Connection Server sends the response to 3rd-party app server upon processing
+the message request. </p>
+
+<h4>Interpreting a downstream HTTP message response </h4>
+<p>The 3rd-party app server should look at both the message response header and the body
+to interpret the message response sent from the GCM Connection Server. The following table
+describes the possible responses.</p>
+<p>
+
+<p class="table-caption" id="table3">
+  <strong>Table 3.</strong> Downstream HTTP message response header.</p>
+<table border=1>
+  <tr>
+    <th>Response</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>Message was processed successfully. The response body will contain more
+details about the message status, but its format will depend whether the request
+was JSON or plain text. See <a href="#table4">table 4</a>
+for more details.</td>
+  </tr>
+  <tr>
+    <td>400</td>
+    <td>Only applies for JSON requests.
+Indicates that the request could not be parsed as JSON, or it contained invalid
+fields (for instance, passing a string where a number was expected). The exact
+failure reason is described in the response and the problem should be addressed
+before the request can be retried.</td>
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>There was an error authenticating the sender account.
+<a href="server.html#auth_error">Troubleshoot</a></td>
+  </tr>
+  <tr>
+    <td>5xx</td>
+    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was
+an internal error in the GCM server while trying to process the request, or that
+the server is temporarily unavailable (for example, because of timeouts). Sender
+must retry later, honoring any <code>Retry-After</code> header included in the
+response. Application servers must implement exponential back-off.
+<a href="server.html#internal_error">Troubleshoot</a></td>
+  </tr>
+</table>
+
+<p>The following table lists the fields in a downstream message response body
+(JSON).</p>
+
+
+<p class="table-caption" id="table4">
+  <strong>Table 4.</strong> Downstream HTTP message response body (JSON).</p>
+<table>
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>multicast_id</code></td>
+    <td>Required, number</td>
+    <td>Unique ID (number) identifying the multicast message.</td>
+  </tr>
+  <tr>
+    <td><code>success</code></td>
+    <td>Required, number</td>
+    <td>Number of messages that were processed without an error.</td>
+  </tr>
+  <tr>
+    <td><code>failure</code></td>
+    <td>Required, number</td>
+    <td>Number of messages that could not be processed.</td>
+  </tr>
+  <tr>
+    <td><code>canonical_ids</code></td>
+    <td>Required, number</td>
+    <td>Number of results that contain a canonical registration ID. See the
+<a href="{@docRoot}google/gcm/gcm.html#canonical">Overview</a> for more discussion of this topic.</td>
+  </tr>
+  <tr>
+    <td><code>results</code></td>
+    <td>Optional, array object</td>
+    <td>Array of objects representing the status of the messages processed. The
+objects are listed in the same order as the request (i.e., for each registration
+ID in the request, its result is listed in the same index in the response).<br>
+      <ul>
+        <li><code>message_id</code>: String specifying a unique ID for each successfully processed
+          message.</li>
+        <li><code>registration_id</code>: Optional string specifying the canonical registration ID
+          for the client app that the message was processed and sent to. Sender should use this
+          value as the Registration ID for future requests. Otherwise, the messages might
+          be rejected.
+        </li>
+        <li><code>error</code>: String specifying the error that occurred when processing the
+          message for the recipient. The possible values can be found in <a href="#table11">table 11
+        </a>.</li>
+    </ul></td>
+  </tr>
+</table>
+
+
+<p class="table-caption" id="table5">
+  <strong>Table 5.</strong> Success response for downstream HTTP message response body (Plain Text).</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>id</code></td>
+    <td>Required, string</td>
+    <td>This parameter specifies the unique message ID that GCM server processed successfully.</td>
+  </tr>
+  <tr>
+    <td><code>registration_id</code></td>
+    <td>Optional, string</td>
+    <td>This parameter specifies the canonical registration ID for the client app that the message was
+processed and sent to. Sender should replace the registration ID with this value on future requests,
+otherwise, the messages might be rejected.</td>
+  </tr>
+</table>
+
+<p class="table-caption" id="table6">
+  <strong>Table 6.</strong> Error response for downstream HTTP message response body (Plain Text).</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>{@code Error}</td>
+    <td>Required, string</td>
+    <td>This parameter specifies the error value while processing the message for the recipient.
+See <a href="#table11">table 11</a> for details. </td>
+  </tr>
+</table>
+
+<h4>Interpreting a downstream XMPP message response</h4>
+
+<p>The following table lists the fields that appear in a downstream XMPP message response.</p>
+
+<p class="table-caption" id="table7">
+  <strong>Table 7.</strong> Downstream message XMPP message response body.</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>from</code></td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies who sent this response.</p>
+    <p>The value is the registration ID of the client app.</p></td>
+  </tr>
+  <tr>
+    <td><code>message_id</code></td>
+    <td>Required, string</td>
+    <td>This parameter uniquely identifies a message in an XMPP connection.
+The value is a string that uniquely identifies the associated message.</td>
+  </tr>
+  <tr>
+    <td><code>message_type</code></td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies an 'ack' or 'nack' message from XMPP (CCS)
+to the 3rd-party app server.</p>
+    <p>If the value is set to {@code nack}, the 3rd-party app server should look at
+{@code error} and {@code error_description} to get failure information. </p></td>
+  </tr>
+  <tr>
+    <td><code>error</code></td>
+    <td>Optional, string</td>
+    <td>This parameter specifies an error related to the downstream message. It is set when the
+{@code message_type} is {@code nack}. See <a href="#table11">table 6</a> for details.</td>
+  </tr>
+  <tr>
+    <td><code>error_description</code></td>
+    <td>Optional, string</td>
+    <td>This parameter provides descriptive information for the error. It is set
+when the {@code message_type} is {@code nack}.</td>
+  </tr>
+</table>
+<h2 id="upstream">Upstream Messages (XMPP)</h2>
+
+<p>An upstream message is a message the client app sends to the 3rd-party app server.
+Currently only CCS (XMPP) supports upstream messaging.</p>
+
+<h3 id="interpret-upstream">Interpreting an upstream XMPP message </h3>
+<p>The following table describes the fields that appear in an upstream XMPP message.
+
+<p class="table-caption" id="table8">
+  <strong>Table 8.</strong> Upstream XMPP messages.</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>from</code></td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies who sent the message.</p>
+    <p>The value is the registration ID of the client app.</p></td>
+  </tr>
+  <tr>
+    <td><code>category</code></td>
+    <td>Required, string</td>
+    <td>This parameter specifies the application package name of the client app that sent the message. </td>
+  </tr>
+  <tr>
+    <td><code>message_id</code></td>
+    <td>Required, string</td>
+    <td>This parameter specifies the unique ID of the message. </td>
+  </tr>
+  <tr>
+    <td><code>data</code></td>
+    <td>Optional, string</td>
+    <td>This parameter specifies the key-value pairs of the message's payload.</td>
+  </tr>
+</table>
+
+<h3 id="upstream-response">Sending an upstream XMPP message response</h3>
+
+<p>The following table describes the response that 3rd-party app server is expected to send to
+<a href="{@docRoot}google/gcm/ccs.html">XMPP (CCS)</a> in response to an
+upstream message it (the app server) received.</p>
+
+<p class="table-caption" id="table9">
+  <strong>Table 9.</strong> Upstream XMPP message response.</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>to</code></td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies the recipient of a response message. </p>
+    <p>The value must be a registration ID of the client app that sent the upstream message.</p></td>
+  </tr>
+  <tr>
+    <td><code>message_id</code></td>
+    <td>Required, string</td>
+    <td>This parameter specifies which message the response is intended for. The value must be
+the {@code message_id} value from the corresponding upstream message.</td>
+  </tr>
+  <tr>
+    <td><code>message_type</code></td>
+    <td>Required, string</td>
+    <td>This parameter specifies an {@code ack} message from a 3rd-party app server to CCS.</td>
+  </tr>
+</table>
+<h2 id="ccs">Cloud Connection Server Messages (XMPP) </h2>
+<p>This is a message sent from XMPP (CCS) to a 3rd-party app server. Here are the primary types
+of messages that XMPP (CCS) sends to the 3rd-party app server:</p>
+<ul>
+  <li><strong>Delivery Receipt:</strong> If the 3rd-party app server included {@code delivery_receipt_requested}
+in the downstream message, XMPP (CCS) sends a delivery receipt when it receives confirmation
+that the device received the message.</li>
+  <li><strong>Control:</strong> These CCS-generated messages indicate that
+action is required from the 3rd-party app server.</li>
+</ul>
+
+<p>The following table describes the fields included in the messages CCS
+sends to a 3rd-party app server.</p>
+
+<p class="table-caption" id="table10">
+  <strong>Table 10.</strong> GCM Cloud Connection Server messages (XMPP).</p>
+<table border="1">
+  <tr>
+    <th>Parameter</th>
+    <th>Usage</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td colspan="3"><strong>Common Field</strong></td>
+  </tr>
+  <tr>
+    <td><code>message_type</code></td>
+    <td>Required, string</td>
+    <td><p>This parameter specifies the type of the CCS message: either delivery receipt or control.</p>
+      <p>When it is set to {@code receipt}, the message includes {@code from}, {@code message_id},
+        {@code category} and {@code data} fields to provide additional information.</p>
+    <p>When it is set to {@code control}, the message includes {@code control_type} to indicate the
+type of control message.</p></td>
+  </tr>
+  <tr>
+    <td colspan="3"><strong>Delivery receipt-specific</strong></td>
+  </tr>
+  <tr>
+    <td><code>from</code></td>
+    <td>Required, string</td>
+    <td>This parameter is set to {@code gcm.googleapis.com}, indicating that the
+message is sent from CCS.</td>
+  </tr>
+  <tr>
+    <td><code>message_id</code></td>
+    <td>Required, string</td>
+    <td>This parameter specifies the original message ID that the receipt is intended for,
+prefixed with {@code dr2:} to indicate that the message is a delivery receipt. A 3rd-party app
+server must send an {@code ack} message with this message ID to acknowledge that it
+received this delivery receipt. See <a href="#table9">table 9</a> for the 'ack' message format.</td>
+  </tr>
+  <tr>
+    <td><code>category</code></td>
+    <td>Optional, string</td>
+    <td>This parameter specifies the application package name of the client app that
+receives the message that this delivery receipt is reporting. This is available when
+{@code message_type} is {@code receipt}.</td>
+  </tr>
+  <tr>
+    <td><code>data</code></td>
+    <td>Optional, string</td>
+    <td>This parameter specifies the key-value pairs for the delivery receipt message. This is available
+when the {@code message_type} is {@code receipt}.
+      <ul>
+        <li>{@code message_status}: This parameter specifies the status of the receipt message.
+It is set to {@code MESSAGE_SENT_TO_DEVICE} to indicate the device has confirmed its receipt of
+the original message.</li>
+      <li>{@code original_message_id}: This parameter specifies the ID of the original message
+that the 3rd-party app server sent to the client app.</li>
+     <li>{@code device_registration_id}: This parameter specifies the registration ID of the
+client app to which the original message was sent.</li>
+    </ul>
+</td>
+  </tr>
+  <tr>
+    <td colspan="3"><strong>Control-specific</strong></td>
+  </tr>
+  <tr>
+    <td><code>control_type</code></td>
+    <td>Optional, string</td>
+    <td><p>This parameter specifies the type of control message sent from CCS.</p>
+    <p>Currently, only {@code CONNECTION_DRAINING} is supported. XMPP (CCS) sends this control message
+before it closes a connection to perform load balancing. As the connection drains, no more messages
+are allowed to be sent to the connection, but existing messages in the pipeline will
+continue to be processed.</p></td>
+  </tr>
+</table>
+
+<h2 id="error-codes">Downstream message error response codes (HTTP and XMPP)</h2>
+
+<p>The following table lists the error response codes for downstream messages (HTTP and XMPP).</p>
+
+<p class="table-caption" id="table11">
+  <strong>Table 11.</strong> Downstream message error response codes.</p>
+<table border="1">
+  <tr>
+    <th>Error</th>
+    <th>HTTP Code</th>
+    <th>XMPP Code</th>
+    <th>Recommended Action</th>
+  </tr>
+  <tr>
+    <td>Missing Registration ID</td>
+    <td>200 + error:MissingRegistration</td>
+    <td><code>INVALID_JSON</code></td>
+    <td>Check that the request contains a registration ID (either in the
+{@code registration_id} in a plain text message, or in the {@code registration_ids} in JSON).</td>
+  </tr>
+  <tr>
+    <td>Invalid Registration ID</td>
+    <td>200 + error:InvalidRegistration</td>
+    <td><code>BAD_REGISTRATION</code></td>
+    <td>Check the format of the registration ID you pass to the server. Make sure it
+matches the registration ID the client app receives from registering with GCM. Do not
+truncate or add additional characters.</td>
+  </tr>
+  <tr>
+    <td>Unregistered Device</td>
+    <td>200 + error:NotRegistered</td>
+    <td><code>DEVICE_UNREGISTERED</code></td>
+    <td>An existing registration ID may cease to be valid in a number of scenarios, including:<br>
+     <ul>
+      <li>If the client app unregisters with GCM.</li>
+      <li>If the client app is automatically unregistered, which can happen if the user uninstalls the application.</li>
+      <li>If the registration ID expires (for example, Google might decide to refresh registration IDs).</li>
+      <li>If the client app is updated but the new version is not configured to receive messages.</li>
+</ul>
+ For all these cases, remove this registration ID from the 3rd-party app
+server and stop using it to send messages.</td>
+  </tr>
+  <tr>
+    <td>Invalid Package Name</td>
+    <td>200 + error:InvalidPackageName</td>
+    <td></td>
+    <td>Make sure the message was addressed to a registration ID whose package name
+matches the value passed in the request.</td>
+  </tr>
+  <tr>
+    <td>Authentication Error</td>
+    <td>401</td>
+    <td>&nbsp;</td>
+    <td>The sender account used to send a message couldn't be authenticated. Possible causes are:<br>
+<ul>
+      <li>Authorization header missing or with invalid syntax in HTTP request.</li>
+      <li>Invalid project number sent as key.</li>
+      <li>Key valid but with GCM service disabled.</li>
+      <li>Request originated from a server not whitelisted in the Server Key IPs.</li>
+</ul>
+    Check that the token you're sending inside the Authentication header is
+the correct API key associated with your project. See
+<a href="{@docRoot}google/gcm/http.html">GCM HTTP Connection Server</a> for details.</td>
+  </tr>
+  <tr>
+    <td>Mismatched Sender</td>
+    <td>200 + error:MismatchSenderId</td>
+    <td><code>BAD_REGISTRATION</code></td>
+    <td>A registration ID is tied to a certain group of senders. When a client app registers
+for GCM, it must specify which senders are allowed to send messages. You should use one
+of those sender IDs when sending messages to the client app. If you switch to a different
+sender, the existing registration IDs won't work.</td>
+  </tr>
+  <tr>
+    <td>Invalid JSON</td>
+    <td>400</td>
+    <td><code>INVALID_JSON</code></td>
+    <td>Check that the JSON message is properly formatted and contains valid fields
+(for instance, making sure the right data type is passed in).</td>
+  </tr>
+  <tr>
+    <td>Message Too Big</td>
+    <td>200 + error:MessageTooBig</td>
+    <td><code>INVALID_JSON</code></td>
+    <td>Check that the total size of the payload data included in a message does
+not exceed 4096 bytes. This includes both the the keys and the values.</td>
+  </tr>
+  <tr>
+    <td>Invalid Data Key</td>
+    <td>200 + error:
+<br />
+InvalidDataKey</td>
+    <td><code>INVALID_JSON</code></td>
+    <td>Check that the payload data does not contain a key (such as {@code from} or any value
+prefixed by {@code google}) that is used internally by GCM. Note that some words (such as {@code collapse_key})
+are also used by GCM but are allowed in the payload, in which case the payload value
+will be overridden by the GCM value.</td>
+  </tr>
+  <tr>
+    <td>Invalid Time to Live</td>
+    <td>200 + error:InvalidTtl</td>
+    <td><code>INVALID_JSON</code></td>
+    <td>Check that the value used in {@code time_to_live} is an integer representing a
+duration in seconds between 0 and 2,419,200 (4 weeks).</td>
+  </tr>
+  <tr>
+    <td>Bad ACK message</td>
+    <td>N/A</td>
+    <td><code>BAD_ACK</code></td>
+    <td>Check that the 'ack' message is properly formatted before retrying. See
+<a href="#table9">table 9</a> for details.</td>
+  </tr>
+  <tr>
+    <td>Timeout</td>
+    <td>5xx or 200 + error:Unavailable</td>
+    <td><code>SERVICE_UNAVAILABLE</code></td>
+    <td><p>The server couldn't process the request in time. Retry the same request, but you must:<br>
+<ul>
+      <li>For HTTP: Honor the {@code Retry-After} header if it is included in the response from the
+GCM Connection Server.</li>
+      <li>Implement exponential back-off in your retry mechanism. (e.g. if you waited one second
+before the first retry, wait at least two second before the next one, then 4 seconds and so on).
+If you're sending multiple messages, delay each one independently by an additional random amount
+to avoid issuing a new request for all messages at the same time.</li>
+    <li>For CCS: The initial retry delay should be set to 1 second.</li>
+</ul>
+    <p>Senders that cause problems risk being blacklisted.</p></td>
+  </tr>
+  <tr>
+    <td>Internal Server Error</td>
+    <td>500 or 200 + error:InternalServerError</td>
+    <td><code>INTERNAL_SERVER_
+<br />
+ERROR</code></td>
+    <td>The server encountered an error while trying to process the request. You could retry
+the same request following the requirements listed in "Timeout" (see row above). If the error persists, please
+report the problem in the {@code android-gcm group}.</td>
+  </tr>
+  <tr>
+    <td>Device Message Rate Exceeded</td>
+    <td>200 + error:
+<br />DeviceMessageRate
+<br />
+Exceeded</td>
+    <td><code>DEVICE_MESSAGE_RATE<br />
+_EXCEEDED</code></td>
+    <td>The rate of messages to a particular device is too high. Reduce the
+number of messages sent to this device and do not immediately retry sending to this device.</td>
+  </tr>
+  <tr>
+    <td>Connection Draining</td>
+    <td>N/A</td>
+    <td><code>CONNECTION_DRAINING</code></td>
+    <td>The message couldn't be processed because the connection is draining. This happens because
+periodically, XMPP (CCS) needs to close down a connection to perform load balancing. Retry the message over
+another XMPP connection.</td>
+  </tr>
+</table>
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index 20e2b2e..004fd0e 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -7,9 +7,9 @@
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#choose">Choosing a GCM Connection Server</a></li>
   <li><a href="#role">Role of the 3rd-party Application Server</a></li>
-    <li><a href="#send-msg">Sending Messages</a>
+  <li><a href="#choose">Choosing a GCM Connection Server</a></li>
+  <li><a href="#send-msg">Sending Messages</a>
     <ol class="toc">
 
       <li><a href="#target">Target</a></li>
@@ -17,7 +17,18 @@
       <li><a href="#params">Message parameters</a>
     </ol>
     </li>
-  <li><a href="#receive">Receiving Messages</a> </li>
+  <li><a href="#adv">Messaging Concepts and Best Practices</a>
+
+   <ol class="toc">
+
+      <li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a></li>
+      <li><a href="#ttl">Setting an Expiration Date for a Message</a></li>
+      <li><a href="#multi-senders">Receiving Messages from Multiple Senders</a>
+      <li><a href="#lifetime">Lifetime of a Message</a>
+      <li><a href="#throttling">Throttling</a>
+    </ol>
+
+</li>
   </li>
 
 </ol>
@@ -25,6 +36,7 @@
 <h2>See Also</h2>
 
 <ol class="toc">
+<li><a href="server-ref.html">Server Reference</a></li>
 <li><a href="gs.html">Getting Started</a></li>
 <li><a href="client.html">Implementing GCM Client</a></li>
 <li><a href="ccs.html">Cloud Connection Server (XMPP)</a></li>
@@ -37,79 +49,28 @@
 </div>
 
 
-<p>The server side of Google Cloud Messaging (GCM) consists of 2 components:</p>
+<p>The server side of Google Cloud Messaging (GCM) consists of two components:</p>
 <ul>
 <li>Google-provided <strong>GCM Connection Servers</strong>
-take messages from a 3rd-party application server and send them to a GCM-enabled
-Android application (the &quot;client app&quot;) running on a device. For example,
+take messages from a <a href="{@docRoot}google/gcm/server.html#role">3rd-party app server</a>
+and send them to a GCM-enabled
+application (the &quot;client app&quot;) running on a device. For example,
 Google provides connection servers for <a href="{@docRoot}google/gcm/http.html">
-HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP).</li>
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">XMPP (CCS)</a> (XMPP).</li>
 <li>A <strong>3rd-party application server</strong> that you must implement. This application
-server sends data to a GCM-enabled Android application via the chosen GCM connection server.</li>
+server sends data to a GCM-enabled client app via the chosen GCM connection server.</li>
 </ul>
 </p>
 
-<p>Here are the basic steps you follow to implement your 3rd-party app server:</p>
-
-<ul>
-      <li>Decide which GCM connection server(s) you want to use. Note that if you want to use
-      upstream messaging from your client applications, you must use CCS. For a more detailed
-      discussion of this, see <a href="#choose">
-      Choosing a GCM Connection Server</a>.</li>
-      <li>Decide how you want to implement your app server. For example:
-        <ul>
-          <li>If you decide to use the HTTP connection server, you can use the
-GCM server helper library and demo app to help in implementing your app server.</li>
-          <li>If you decide to use the XMPP connection server, you can use
-the provided Python or Java <a href="http://www.igniterealtime.org/projects/smack/">
-Smack</a> demo apps as a starting point.</li>
-        <li>Note that Google AppEngine does not support connections to CCS.</li>
-        </ul>
-      </li>
-    </ul>
-  </li>
-</ul>
-
 <p>A full GCM implementation requires both a client implementation and a server
 implementation. For more
 information about implementing the client side, see <a href="client.html">
 Implementing GCM Client</a>.</p>
 
-<h2 id="choose">Choosing a GCM Connection Server</h2>
-
-<p>Currently GCM provides two connection servers: <a href="{@docRoot}google/gcm/http.html">
-HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP). You can use them
-separately or in tandem. CCS messaging differs from GCM HTTP messaging in the following ways:</p>
-<ul>
-  <li>Upstream/Downstream messages
-    <ul>
-      <li>GCM HTTP: Downstream only: cloud-to-device. </li>
-      <li>CCS: Upstream and downstream (device-to-cloud, cloud-to-device). </li>
-    </ul>
-  </li>
-  <li>Asynchronous messaging
-    <ul>
-      <li>GCM HTTP: 3rd-party app servers send messages as HTTP POST requests and
-wait for a response. This mechanism is synchronous and causes the sender to block
-before sending another message.</li>
-      <li>CCS: 3rd-party app servers connect to Google infrastructure using a
-persistent XMPP connection and send/receive messages to/from all their devices
-at full line speed. CCS sends acknowledgment or failure notifications (in the
-form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
-    </ul>
-  </li>
-
-  <li>JSON
-    <ul>
-      <li>GCM HTTP: JSON messages sent as HTTP POST.</li>
-      <li>CCS: JSON messages encapsulated in XMPP messages.</li>
-    </ul>
-  </li>
-</ul>
 
 <h2 id="role">Role of the 3rd-party Application Server</h2>
 
-<p>Before you can write client Android applications that use the GCM feature, you must
+<p>Before you can write client apps that use the GCM feature, you must
 have an  application server that meets the following criteria:</p>
 
 <ul>
@@ -117,308 +78,363 @@
   <li>Able to  fire off properly formatted requests to the GCM server.</li>
   <li>Able to handle requests and resend them as needed, using
 <a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
-  <li>Able to store the API key and client registration IDs. The
-API key is included in the header of POST requests that send
-messages.</li>
+  <li>Able to store the API key and client registration IDs. In HTTP, the API key is
+included in the header of POST requests that send messages. In XMPP, the API key is
+used in the SASL PLAIN authentication request as a password to authenticate the connection.</li>
  <li>Able to generate message IDs to uniquely identify each message it sends. Message IDs
 should be unique per sender ID.</li>
 </ul>
 
+<p>Here are the basic steps you follow to implement your 3rd-party app server:</p>
+
+<ul>
+      <li>Decide which GCM connection server(s) you want to use. Note that if you want to use
+      upstream messaging from your client applications, you must use XMPP (CCS). For a more detailed
+      discussion of this, see <a href="#choose">
+      Choosing a GCM Connection Server</a>.</li>
+      <li>Decide how you want to implement your app server. We provide helper libraries and code
+samples to assist you with your 3rd-party app server implementation. For example:
+        <ul>
+          <li>If you decide to use the HTTP connection server, you can use the
+GCM server helper library and demo app to help in implementing your app server.</li>
+          <li>If you decide to use the XMPP connection server, you can use
+the provided Python or Java <a href="http://www.igniterealtime.org/projects/smack/">
+Smack</a> demo apps as a starting point.</li>
+        <li>Note that Google AppEngine does not support connections to XMPP (CCS).</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+
+<h2 id="choose">Choosing a GCM Connection Server</h2>
+
+<p>Currently GCM provides two connection servers: <a href="{@docRoot}google/gcm/http.html">
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">XMPP (CCS)</a>. You can use them
+separately or in tandem. XMPP (CCS) messaging differs from HTTP messaging in the following ways:</p>
+<ul>
+  <li>Upstream/Downstream messages
+    <ul>
+      <li>HTTP: Downstream only, cloud-to-device up to 4KB of data. </li>
+      <li>XMPP (CCS): Upstream and downstream (device-to-cloud, cloud-to-device),
+        up to 4 KB of data. </li>
+    </ul>
+  </li>
+  <li>Messaging (synchronous or asynchronous)
+    <ul>
+      <li>HTTP: Synchronous. 3rd-party app servers send messages as HTTP POST requests and
+wait for a response. This mechanism is synchronous and blocks the sender from sending
+another message until the response is received.</li>
+      <li>XMPP (CCS): Asynchronous. 3rd-party app servers send/receive messages to/from all their
+devices at full line speed over persistent XMPP connections.
+XMPP (CCS) sends acknowledgment or failure notifications (in the
+form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
+    </ul>
+  </li>
+
+  <li>JSON
+    <ul>
+      <li>HTTP: JSON messages sent as HTTP POST.</li>
+      <li>XMPP (CCS): JSON messages encapsulated in XMPP messages.</li>
+    </ul>
+  </li>
+  <li>Plain Text
+    <ul>
+      <li>HTTP: Plain Text messages sent as HTTP POST.</li>
+      <li>XMPP (CCS): Not supported.</li>
+    </ul>
+  </li>
+  <li>Multicast downstream send to multiple registration IDs.
+    <ul>
+      <li>HTTP: Supported in JSON message format.</li>
+      <li>XMPP (CCS): Not supported.</li>
+    </ul>
+  </li>
+</ul>
+
+
 <h2 id="send-msg">Sending Messages</h2>
 
+<p>This section gives an overview of sending messages. For details of message syntax,
+see <a href="{@docRoot}google/gcm/server-ref.html">Server Reference</a>.</p>
+
+<h3>Overview</h3>
+
 <p>Here is the general sequence of events that occurs when a 3rd-party application
-server sends a message:</p>
+server sends a message (the details vary depending on the platform):</p>
 <ol>
-  <li>The application server sends a message to GCM servers.</li>
-  <li>Google enqueues and stores the message in case the device is offline.</li>
-  <li>When the device is online, Google sends the message to the device.</li>
-  <li>On the device, the system broadcasts the message to the specified Android
-application via Intent broadcast with proper permissions, so that only the targeted
-Android application gets the message. This wakes the Android application up.
-The Android application does not need to be running beforehand to receive the message.</li>
-  <li>The Android application processes the message. </li>
+  <li>The 3rd-party app server sends a message to GCM servers.</li>
+  <li>The GCM connection server enqueues and stores the message if the device is offline.</li>
+  <li>When the device is online, GCM connection server sends the message to the device.</li>
+  <li>The client app processes the message. </li>
 </ol>
 
-<p>The following sections describe the basic requirements for
-sending messages.</p>
+<h3>Implement send request</h3>
 
-<h3 id="target">Target</h3>
+<p>The following sections describe the basic components involved in
+sending a request. See the <a href="{@docRoot}google/gcm/server-ref.html">Server Reference</a>
+for details.</p>
+
+<h4 id="target">Target</h4>
 <p>Required. When your app server sends a message in GCM, it must specify a target.</p>
-<p>For HTTP you must specify the target as one of:</p>
+<p>For HTTP you must specify the target as one of the following:</p>
 <ul>
 <li><code>registration_ids</code>: For sending to 1 or more devices (up to 1000).
 When you send a message to multiple registration IDs, that is called a multicast message.</li>
 <li><code>notification_key</code>: For sending to multiple devices owned by a single user.</li>
 </ul>
-<p>For CCS (XMPP):</p>
+<p>For CCS (XMPP) you must specify the target as:</p>
 <ul>
-<li>You must specify the target as the &quot;to&quot; field, where the &quot;to&quot;
+<li>{@code to}: This
 field may contain a single registration ID or a notification key.
-CCS does not support multicast messaging.</li>
+XMPP (CCS) does not support multicast messaging.</li>
 </ul>
-<h3 id="payload">Payload</h3>
-<p>Optional. If you are including a payload in the message, you use the <code>data</code>
-parameter to include the payload. This applies for both HTTP and CCS.</p>
 
-<h3 id="params">Message parameters</h3>
+<h4 id="options">Options</h4>
 
-<p>The following table lists the parameters that a 3rd-party app server might
-include in the JSON messages it sends to a connection server. See the "Where Supported"
-column for information about which connection servers support that particular
-parameter.</p>
+<p>There are various options the 3rd-party app server can set when sending a downstream
+message to a client app. See the <a href="{@docRoot}google/gcm/server-ref.html#table1">
+Server Reference</a> for details. Here are a few examples of possible options:</p>
 
-<p class="table-caption" id="table1">
-  <strong>Table 1.</strong> Message Parameters JSON (CCS and HTTP).</p>
-
-<table>
-  <tr>
-    <th>Parameter</th>
-    <th>Description</th>
-<th>Where Supported</th>
-</tr>
-  <td><code>to</code></td>
-<td>In CCS, this parameter is used in place of <code>registration_ids</code> to
-specify the recipient of a message. Its value must be a registration ID.
-The value is a string. Required.</td>
-<td>CCS</td>
-</tr>
-<tr>
-<td><code>message_id</code></td>
-<td>In CCS, this parameter uniquely identifies a message in an XMPP connection.
-The value is a string that uniquely identifies the associated message. Required.</td>
-<td>CCS</td>
-</tr>
-<tr>
-<td><code>message_type</code></td>
-<td>In CCS, this parameter indicates a special status message, typically sent by the system.
-However, your app server also uses this parameter to send an 'ack' or 'nack'
-message back to the CCS connection server. For more discussion of this topic, see
-<a href="ccs.html">Cloud Connection Server</a>. The value is a string. Optional.</td>
-<td>CCS</td>
-<tr>
-  <td><code>registration_ids</code></td>
-  <td>This parameter specifies a string array containing the list of devices
-(registration IDs) receiving the
-message. It must contain at least 1 and at most 1000 registration IDs. To send a
-multicast message, you must use JSON. For sending a single message to a single
-device, you could use a JSON object with just 1 registration id, or plain text
-(see below). A request must include a recipient&mdash;this can be either a
-registration ID, an array of registration IDs, or a {@code notification_key}.
-Required.</td>
-<td>HTTP</td>
-</tr>
- <tr>
-    <td><code>notification_key</code></td>
-    <td>This parameter specifies a string that maps a single user to multiple
-registration IDs associated
-with that user. This allows a 3rd-party server to send a single message to
-multiple app instances (typically on multiple devices) owned by a single user.
-A 3rd-party server can use {@code notification_key} as the target for a message
-instead of an individual registration ID (or array of registration IDs). The maximum
-number of members allowed for a {@code notification_key} is 20. For more discussion
-of this topic, see <a href="notifications.html">User Notifications</a>. Optional.
-</td>
-<td style="width:100px">HTTP. This feature is supported in CCS, but you use it by
-specifying a notification key in the &quot;to&quot; field.</td>
-</tr>
-  <tr>
-    <td><code>collapse_key</code></td>
-    <td>This parameter specifies an arbitrary string (such as
-&quot;Updates Available&quot;) that is used
-to collapse a group of like messages
-when the device is offline, so that only the last message gets sent to the
-client. This is intended to avoid sending too many messages to the phone when it
-comes back online. Note that since there is no guarantee of the order in which
-messages get sent, the &quot;last&quot; message may not actually be the last
-message sent by the application server. Messages with collapse keys are also called
-<a href="#s2s">send-to-sync messages</a>.
-<br>
-<strong>Note:</strong> GCM allows a maximum of 4 different collapse keys to be
-used by the GCM server
-at any given time. In other words, the GCM server can simultaneously store 4
-different send-to-sync messages per device, each with a different collapse key.
-If you exceed
-this number GCM will only keep 4 collapse keys, with no guarantees about which
-ones they will be. See <a href="adv.html#collapsible">Advanced Topics</a> for more
-discussion of this topic. Optional.</td>
-<td>CCS, HTTP</td>
-</tr>
-  <tr>
-    <td><code>data</code></td>
-    <td>This parameter specifies a JSON object whose fields represents the
-key-value pairs of the message's
-payload data. If present, the payload data will be
-included in the Intent as application data, with the key being the extra's name.
-For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra
-named <code>score</code> whose value is the string <code>3x1</code>.
-There is no limit on the number of key/value pairs, though there is a limit on
-the total size of the message (4kb). The values could be any JSON object, but we
-recommend using strings, since the values will be converted to strings in the GCM
-server anyway. If you want to include objects or other non-string data types
-(such as integers or booleans), you have to do the conversion to string yourself.
-Also note that the key cannot be a reserved word (<code>from</code> or any word
-starting with <code>google.</code>). Using words defined in this table as field
-names (such as <code>collapse_key</code>) could yield unpredictable outcomes and
-is not recommended. Optional.</td>
-<td>CCS, HTTP</td>
-</tr>
-  <tr>
-    <td><code>delay_while_idle</code></td>
-    <td>This parameter indicates that the message should not be sent immediately
-if the device is idle. The server will wait for the device to become active, and
-then only the last message for each <code>collapse_key</code> value will be
-sent. The default value is <code>false</code>, and must be a JSON boolean. Optional.</td>
-<td>CCS, HTTP</td>
-</tr>
-  <tr>
-    <td><code>time_to_live</code></td>
-    <td>This parameter specifies how long (in seconds) the message should be kept on GCM
-storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as
-a JSON number).</td>
-<td>CCS, HTTP</td>
-</tr>
-<tr>
-  <td><code>restricted_package_name</code></td>
-  <td>This parameter specifies a string containing the package
-name of your application. When set, messages
-are only sent to registration IDs that match the package name. Optional.
-  </td>
-<td>HTTP</td>
-</tr>
-<tr>
-  <td><code>dry_run</code></td>
-  <td>This parameter allows developers to test a request without actually
-sending a message. Optional. The default value is <code>false</code>, and must
-be a JSON boolean.
-  </td>
-<td>HTTP</td>
-</tr>
-<tr>
-  <td><code>delivery_receipt_requested</code></td>
-  <td>This parameter lets you request confirmation of message delivery. When
-this parameter is set to <code>true</code>, CCS sends a
-delivery receipt when a device confirms that it received a message sent by CCS.
-The default value is <code>false</code>, and must be a JSON boolean. Optional.<br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.
-</td>
-  <td>CCS</td>
-</tr>
-<tr>
-  <td><code>message_status</code></td>
-  <td>This parameter specifies the status of the receipt message.
-The parameter appears inside the
-<code>&quot;data&quot;</code> field of a
-delivery receipt message. Currently the only possible value
-is <code>MESSAGE_SENT_TO_DEVICE</code>, which indicates that a device acknowledges
-receiving  a message sent by CCS.<br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.</td>
-  <td>CCS</td>
-</tr>
-<tr>
-  <td><code>original_message_id</code></td>
-  <td>The value of this parameter is the ID of the original message that the server sent to
-the device. This parameter appears inside the <code>&quot;data&quot;</code> field of a
-delivery receipt message. <br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.</td>
-  <td>CCS</td>
-</tr>
-<tr>
-  <td><code>device_registration_id</code></td>
-  <td>For the purpose of tracking the delivery receipt, this parameter lists
-the registration ID of the device to which a given message was sent. This parameter
-appears inside the <code>&quot;data&quot;</code> field of a
-delivery receipt message. <br />
-This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
-delivery receipts</a>.</td>
-  <td>CCS</td>
-</tr>
-
-</table>
-
+<ul>
+  <li>{@code collapse_key}: whether a message should be "send-to-sync" or a "message with
+payload".</li>
+  <li>{@code time_to_live}: setting an expiration date for a message.</li>
+  <li>{@code dry_run}: Test your server.
 <p>If you want to test your request (either JSON or plain text) without delivering
-the message to the devices, you can set an optional HTTP or JSON parameter called
+the message to the devices, you can set an optional HTTP parameter called
 <code>dry_run</code> with the value <code>true</code>. The result will be almost
 identical to running the request without this parameter, except that the message
 will not be delivered to the devices. Consequently, the response will contain fake
 IDs for the message and multicast parameters.</p>
+</li>
+</ul>
 
-<p>If you are using plain text instead of JSON, the message parameters must be set as
-HTTP parameters sent in the body, and their syntax is slightly different, as
-described in the following table:
+<h4 id="payload">Payload</h4>
+<p>Optional. If you are including a payload in the message, you use the <code>data</code>
+parameter to include the payload. This applies for both HTTP and XMPP.</p>
 
-<p class="table-caption" id="table2">
-  <strong>Table 2.</strong> Message Parameters Plain Text (HTTP only).</p>
-<table>
-  <tr>
-    <th>Parameter</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>registration_id</code></td>
-    <td>This parameter specifies the registration ID of the single device
-receiving the message.
-Required.</td>
-  </tr>
-  <tr>
-    <td><code>collapse_key</code></td>
-    <td>Same as JSON (see previous table). Optional.</td>
-  </tr>
-  <tr>
-    <td><code>data.&lt;key&gt;</code></td>
+<p>See the <a href="{@docRoot}google/gcm/server-ref.html">Server Reference</a> for details on sending
+and receiving messages.</p>
 
-    <td>This parameter specifies payload data, expressed as parameters
-prefixed with <code>data.</code> and
-suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would
-result in an intent extra named <code>score</code> whose value is the string
-<code>3x1</code>. There is no limit on the number of key/value parameters, though
-there is a limit on the total size of the  message. Also note that the key cannot
-be a reserved word (<code>from</code> or any word starting with
-<code>google.</code>). Using words defined in this table as field
-names (such as <code>collapse_key</code>) could yield unpredictable outcomes and
-is not recommended. Optional.</td>
+<h2 id="adv">Messaging Concepts and Best Practices</h2>
 
-  </tr>
-  <tr>
-    <td><code>delay_while_idle</code></td>
-    <td>This parameter specifies whether messages should be delivered when the device
-is asleep. A value of <code>1</code> or <code>true</code> indicates
-<code>true</code>, and anything else indicates <code>false</code>. Optional. The default
-value is <code>false</code>.</td>
-  </tr>
-  <tr>
-    <td><code>time_to_live</code></td>
-    <td>Same as JSON (see previous table). Optional.</td>
-  </tr>
-<tr>
-  <td><code>restricted_package_name</code></td>
-  <td>Same as JSON (see previous table). Optional.
-  </td>
-</tr>
-<tr>
-  <td><code>dry_run</code></td>
-  <td>Same as JSON (see previous table). Optional.
-  </td>
-</tr>
-</table>
+<p>This section has a discussion of general messaging topics.</p>
 
-<h2 id="receive">Receiving Messages</h2>
+<h3 id="collapsible">Send-to-Sync  vs. Messages with Payload</h3>
 
-<p>This is the sequence of events that occurs when an Android application
-installed on a mobile device receives a message:</p>
+<p>Every message sent in GCM has the following characteristics:</p>
+<ul>
+  <li>It has a payload limit of 4096 bytes.</li>
+  <li>By default, it is stored by GCM for 4 weeks.</li>
+</ul>
 
-<ol>
-  <li>The system receives the incoming message and extracts the raw key/value
-pairs from the message payload, if any.</li>
-  <li>The system passes the key/value pairs to the targeted Android application
-in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
-extras.</li>
-  <li>The Android application extracts the raw data
-from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
-by key and processes the data.</li>
-</ol>
+<p>But despite these similarities, messages can behave very differently depending
+on their particular settings. One major distinction between messages is whether
+they are collapsed (where each new message replaces the preceding message) or not
+collapsed (where each individual message is delivered). Every message sent in GCM
+is either a &quot;send-to-sync&quot; (collapsible) message or a &quot;message with
+payload&quot; (non-collapsible message).</p>
 
-<p>See the documentation for each connection server for more detail on how it
-handles responses.</p>
+<h4 id="s2s">Send-to-sync messages</h4>
+
+<p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells
+a mobile application to sync data from the server. For example, suppose you have
+an email application. When a user receives new email on the server, the server
+pings the mobile application with a &quot;New mail&quot; message. This tells the
+application to sync to the server to pick up the new email. The server might send
+this message multiple times as new mail continues to accumulate, before the application
+has had a chance to sync. But if the user has received 25 new emails, there's no
+need to preserve every &quot;New mail&quot; message. One is sufficient. Another
+example would be a sports application that updates users with the latest score.
+Only the most recent message is relevant. </p>
+
+<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
+at any given time. In other words, the GCM server can simultaneously store 4
+different send-to-sync messages per device, each with a different collapse key.
+For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
+and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
+guarantees about which ones they will be.</p>
+
+<h3 id="payload">Messages with payload</h3>
+
+<p>Unlike a send-to-sync message, every &quot;message with payload&quot;
+(non-collapsible message) is delivered. The payload the message contains can be
+up to 4kb. For example, here is a JSON-formatted message in an IM application in
+which spectators are discussing a sporting event:</p>
+
+<pre class="prettyprint pretty-json">{
+  "registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
+  "data" : {
+    "Nick" : "Mario",
+    "Text" : "great match!",
+    "Room" : "PortugalVSDenmark",
+  },
+}</pre>
+
+<p>A &quot;message with payload&quot; is not simply a &quot;ping&quot; to the
+mobile application to contact the server to fetch data. In the aforementioned IM
+application, for example, you would want to deliver every message, because every
+message has different content. To specify a non-collapsible message, you simply
+omit the <code>collapse_key</code> parameter. Thus GCM will send each message
+individually. Note that the order of delivery is not guaranteed.</p>
+
+<p>GCM will store up to 100 non-collapsible messages. After that, all messages
+are discarded from GCM, and a new message is created that tells the client how
+far behind it is.</p>
+
+<p>The application should respond by syncing with the server to recover the
+discarded messages. </p>
+
+<h4 id="which">Which should I use?</h4>
+  <p>If your application does not need to use non-collapsible messages, collapsible
+messages are a better choice from a performance standpoint. However, if you use
+collapsible messages, remember that <strong>GCM only allows a maximum of 4 different collapse
+keys to be used by the GCM server per registration ID at any given time</strong>. You must
+not exceed this number, or it could cause unpredictable consequences.</p>
+
+<h3 id="ttl">Setting an Expiration Date for a Message</h3>
+<p>You can use the <code>time_to_live</code> parameter in the send request
+to specify the maximum lifespan of a message.
+The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
+it corresponds to the maximum period of time for which GCM will store and try to
+deliver the message. Requests that don't contain this field default to the maximum
+period of 4 weeks.</p>
+<p>Here are some possible uses for this feature:</p>
+<ul>
+  <li>Video chat incoming calls</li>
+  <li>Expiring invitation events</li>
+  <li>Calendar events</li>
+</ul>
+<h4 id="bg">Background </h4>
+<p>GCM usually delivers messages immediately after they are sent. However,
+this might not always be possible. For example, if the platform is Android,
+the device could be turned off, offline, or otherwise unavailable.
+Or the sender itself might request
+that messages not be delivered until the device becomes active by using the
+<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
+to prevent an application from consuming excessive resources and negatively
+impacting battery life.</p>
+
+<p>When this happens, GCM will store the message and deliver it as soon as it's
+feasible. While this is fine in most cases, there are some applications for which
+a late message might as well never be delivered. For example, if the message is
+an incoming call or video chat notification, it will only be meaningful for a
+small period of time before the call is terminated. Or if the message is an
+invitation to an event, it will be useless if received after the event has ended.</p>
+
+<p>Another advantage of specifying the expiration date for a message is that GCM
+will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
+In other words, GCM will guarantee best effort for messages that must be delivered
+&quot;now or never.&quot; Keep in mind that a <code>time_to_live</code> value of
+0 means messages that can't be delivered immediately will be discarded. However,
+because such messages are never stored, this provides the best latency for
+sending notifications.</p>
+
+<p>Here is an example of a JSON-formatted request that includes TTL:</p>
+<pre class="prettyprint pretty-json">
+{
+  "collapse_key" : "demo",
+  "delay_while_idle" : true,
+  "registration_ids" : ["xyz"],
+  "data" : {
+    "key1" : "value1",
+    "key2" : "value2",
+  },
+  "time_to_live" : 3
+},
+</pre>
+
+
+<h3 id="multi-senders">Receiving Messages from Multiple Senders</h3>
+
+<p>GCM allows multiple parties to send messages to the same application. For
+example, suppose your application is an articles aggregator with multiple
+contributors, and you want each of them to be able to send a message when they
+publish a new article. This message might contain a URL so that the application
+can download the article. Instead of having to centralize all sending activity in
+one location, GCM gives you the ability to let each of these contributors send
+its own messages.</p>
+
+<p>To make this possible, all you need to do is have each sender generate its own
+project number. Then include those IDs in the sender field, separated by commas,
+when requesting a registration. Finally, share the registration ID with your
+partners, and they'll be able to send messages to your application using their
+own authentication keys.</p>
+
+<p>Note that there is limit of 100 multiple senders.</p>
+
+<h3 id="lifetime">Lifetime of a Message</h3>
+
+<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
+it does not mean that the message was already delivered to the device. Rather, it
+means that it was accepted for delivery. What happens to the message after it is
+accepted depends on many factors.</p>
+
+<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
+and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
+the message will be delivered right away.</p>
+
+<p>If the device is connected but idle, the message will still be
+delivered right away unless the <code>delay_while_idle</code> flag is set to true.
+Otherwise, it will be stored in the GCM servers until the device is awake. And
+that's where the <code>collapse_key</code> flag plays a role: if there is already
+a message with the same collapse key (and registration ID) stored and waiting for
+delivery, the old message will be discarded and the new message will take its place
+(that is, the old message will be collapsed by the new one). However, if the collapse
+key is not set, both the new and old messages are stored for future delivery.
+Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
+
+<p class="note"><strong>Note:</strong> There is a limit on how many messages can
+be stored without collapsing. That limit is currently 100. If the limit is reached,
+all stored messages are discarded. Then when the device is back online, it receives
+a special message indicating that the limit was reached. The application can then
+handle the situation properly, typically by requesting a full sync.
+<br><br>
+Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
+a particular device. GCM allows a maximum of 4 different collapse keys to be used
+by the GCM server per device
+any given time. In other words, the GCM server can simultaneously store 4 different
+send-to-sync messages, each with a different collapse key. If you exceed this number
+GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
+See <a href="#s2s">Send-to-sync messages</a> for more information.
+</p>
+
+<p>If the device is not connected to GCM, the message will be stored until a
+connection is established (again respecting the collapse key rules). When a connection
+is established, GCM will deliver all pending messages to the device, regardless of
+the <code>delay_while_idle</code> flag. If the device never gets connected again
+(for instance, if it was factory reset), the message will eventually time out and
+be discarded from GCM storage. The default timeout is 4 weeks, unless the
+<code>time_to_live</code> flag is set.</p>
+
+<p>Finally, when GCM attempts to deliver a message to the device and the
+application was uninstalled, GCM will discard that message right away and
+invalidate the registration ID. Future attempts to send a message to that device
+will get a <code>NotRegistered</code> error. See <a href="#unreg">
+How Unregistration Works</a> for more information.</p>
+<p>Although is not possible to track the status of each individual message, the
+Google Cloud Console stats are broken down by messages sent to device, messages
+collapsed, and messages waiting for delivery.</p>
+
+<h3 id="throttling">Throttling</h3>
+<p>To prevent abuse (such as sending a flood of messages to a device) and
+to optimize for the overall network efficiency and battery life of
+devices, GCM implements throttling of messages using a token bucket
+scheme. Messages are throttled on a per application and per <a href="#collapsible">collapse
+key</a> basis (including non-collapsible messages). Each application
+collapse key is granted some initial tokens, and new tokens are granted
+periodically therefter. Each token is valid for a single message sent to
+the device. If an application collapse key exhausts its supply of
+available tokens, new messages are buffered in a pending queue until
+new tokens become available at the time of the periodic grant. Thus
+throttling in between periodic grant intervals may add to the latency
+of message delivery for an application collapse key that sends a large
+number of messages within a short period of time. Messages in the pending
+queue of an application collapse key may be delivered before the time
+of the next periodic grant, if they are piggybacked with messages
+belonging to a non-throttled category by GCM for network and battery
+efficiency reasons.</p>
+
+
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 0c48a0a..4e8e638 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -169,22 +169,15 @@
               <span class="en">HTTP</span></a></li>
               </ul>
         </li>
+        <li><a href="<?cs var:toroot?>google/gcm/server-ref.html">
+            <span class="en">Server Reference</span></a>
+        </li>
         <li><a href="<?cs var:toroot?>google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="<?cs var:toroot?>google/gcm/adv.html">
-            <span class="en">Advanced Topics</span></a>
-        </li>
         <li><a href="<?cs var:toroot?>google/gcm/c2dm.html">
             <span class="en">Migration</span></a>
         </li>
-        <li id="gcm-tree-list" class="nav-section">
-          <div class="nav-section-header">
-            <a href="<?cs var:toroot ?>reference/gcm-packages.html">
-              <span class="en">Reference</span>
-            </a>
-          <div>
-        </li>
       </ul>
   </li>
 
diff --git a/docs/html/google/play-services/ads.jd b/docs/html/google/play-services/ads.jd
index e4f0b2c..2f915f3 100644
--- a/docs/html/google/play-services/ads.jd
+++ b/docs/html/google/play-services/ads.jd
@@ -98,10 +98,8 @@
     serve banner and interstitial ads using the Google Mobile Ads APIs.</p>
 
     <h4>3. Read the documentation</h4>
-    <p>Read the <a class="external-link" href="https://www.google.com/adsense/localized-terms">AdSense
-    Terms of Service</a> and the <a class="external-link"
-    href="https://support.google.com/admob/topic/1307235?hl=en&ref_topic=1307209">AdMob
-    publisher guidelines and policies</a>.</p>
+    <p>Your use of the Google Mobile Ads SDK is governed by the terms between you and Google that
+    govern your use of the Google product (AdSense/AdMob, AdX or DFP) with which you use the SDK.</p>
     <p>For quick access while developing your Android apps, the <a
     href="{@docRoot}reference/gms-packages.html">Google Mobile Ads API reference</a> is available here on
     developer.android.com.</p>
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 1ee6606..0a96a15 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -433,8 +433,8 @@
 <p>To change the locale in the emulator by using the adb shell. </p>

 

 <ol>

-  <li>Pick the locale you want to test and determine its language and region codes, for

-example <code>fr</code> for French and <code>CA</code> for Canada.<br>

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

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

   </li>

   <li>Launch an emulator.</li>

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

@@ -444,16 +444,14 @@
 the <code>-e</code> option:<br>

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

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

-    <code>setprop persist.sys.language  [<em>language code</em>];setprop

-persist.sys.country [<em>country  code</em>];stop;sleep 5;start <br>

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

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

 1.</li>

 </ol>

 

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

 

-<p><code>setprop persist.sys.language  fr;setprop persist.sys.country

-CA;stop;sleep 5;start </code></p>

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

 

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

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

diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
index ec89e37..a02fd89 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
index cf0c63d..c309ac5 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
index f226a54..414fad4 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
new file mode 100644
index 0000000..c147a87
--- /dev/null
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
index ded0645..4ce2125 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle-projected.png b/docs/html/images/opengl/ogl-triangle-projected.png
index 4b18b98..a561bc5 100644
--- a/docs/html/images/opengl/ogl-triangle-projected.png
+++ b/docs/html/images/opengl/ogl-triangle-projected.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle-touch.png b/docs/html/images/opengl/ogl-triangle-touch.png
index 8323dd9..67c4466 100644
--- a/docs/html/images/opengl/ogl-triangle-touch.png
+++ b/docs/html/images/opengl/ogl-triangle-touch.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle.png b/docs/html/images/opengl/ogl-triangle.png
index 66047ab..f51c0c6 100644
--- a/docs/html/images/opengl/ogl-triangle.png
+++ b/docs/html/images/opengl/ogl-triangle.png
Binary files differ
diff --git a/docs/html/images/tv/app-browse.png b/docs/html/images/tv/app-browse.png
new file mode 100644
index 0000000..7670713
--- /dev/null
+++ b/docs/html/images/tv/app-browse.png
Binary files differ
diff --git a/docs/html/images/tv/card-view.png b/docs/html/images/tv/card-view.png
new file mode 100644
index 0000000..5e907de
--- /dev/null
+++ b/docs/html/images/tv/card-view.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index e74d46a..af6f6b8 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -481,14 +481,14 @@
 
 <ul>
 <li>GNOME or KDE desktop</li>
-<li>GNU C Library (glibc) 2.11 or later</li>
+<li>GNU C Library (glibc) 2.15 or later</li>
 <li>2 GB RAM minimum, 4 GB RAM recommended</li>
 <li>400 MB hard disk space</li>
 <li>At least 1 GB for Android SDK, emulator system images, and caches</li>
 <li>1280 x 800 minimum screen resolution</li>
 <li>Oracle&reg;  Java Development Kit (JDK) 7 </li>
 </ul>
-<p>Tested on Ubuntu&reg;  12.04, Precise Pangolin (64-bit distribution capable of running
+<p>Tested on Ubuntu&reg;  14.04, Trusty Tahr (64-bit distribution capable of running
 32-bit applications).</p>
 
 
diff --git a/docs/html/tools/devices/emulator.jd b/docs/html/tools/devices/emulator.jd
index 42240b9..5bdd4e2 100644
--- a/docs/html/tools/devices/emulator.jd
+++ b/docs/html/tools/devices/emulator.jd
@@ -122,7 +122,7 @@
 mobile devices, including: </p>
 
 <ul>
-  <li>An ARMv5 CPU and the corresponding memory-management unit (MMU)</li>
+  <li>An ARMv5, ARMv7, or x86 CPU</li>
   <li>A 16-bit LCD display</li>
   <li>One or more keyboards (a Qwerty-based keyboard and associated Dpad/Phone
 buttons)</li>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 079dd71..0f0a0c0 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -143,10 +143,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:support-v4:21.0.+
+com.android.support:support-v4:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
 
 
 <h2 id="multidex">Multidex Support Library</h2>
@@ -171,10 +170,9 @@
 </p>
 
 <pre>
-com.android.support:multidex:1.0.+
+com.android.support:multidex:1.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 1.0 prefix.</p>
 
 
 <h2 id="v7">v7 Support Libraries</h2>
@@ -226,10 +224,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:appcompat-v7:21.0.+
+com.android.support:appcompat-v7:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
 
 
 <h3 id="v7-cardview">v7 cardview library</h3>
@@ -249,10 +246,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:cardview-v7:21.0.+
+com.android.support:cardview-v7:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
 
 
 <h3 id="v7-gridlayout">v7 gridlayout library</h3>
@@ -271,10 +267,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:gridlayout-v7:21.0.+
+com.android.support:gridlayout-v7:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
 
 
 <h3 id="v7-mediarouter">v7 mediarouter library</h3>
@@ -308,7 +303,7 @@
 where "&lt;revision&gt;" is the minimum revision at which the library is available. For example:</p>
 
 <pre>
-com.android.support:mediarouter-v7:21.0.+
+com.android.support:mediarouter-v7:21.0.0
 </pre>
 
 <p class="caution">The v7 mediarouter library APIs introduced in Support Library
@@ -335,11 +330,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:palette-v7:21.0.+
+com.android.support:palette-v7:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
-
 
 
 <h3 id="v7-recyclerview">v7 recyclerview library</h3>
@@ -360,11 +353,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:recyclerview-v7:21.0.+
+com.android.support:recyclerview-v7:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
-
 
 
 <h2 id="v8">v8 Support Library</h2>
@@ -405,11 +396,9 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:support-v13:18.0.+
+com.android.support:support-v13:18.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 18.0 prefix.</p>
-
 
 
 <h2 id="v17-leanback">v17 Leanback Library</h2>
@@ -448,9 +437,8 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:leanback-v17:21.0.+
+com.android.support:leanback-v17:21.0.0
 </pre>
 
-<p>This dependency notation specifies the latest release version with the 21.0 prefix.</p>
 
 
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 4698ba1..b9463e4 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -153,7 +153,8 @@
 
 <pre>
 PackageManager packageManager = {@link android.content.Context#getPackageManager()};
-List&lt;ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
+List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,
+        PackageManager.MATCH_DEFAULT_ONLY);
 boolean isIntentSafe = activities.size() > 0;
 </pre>
 
diff --git a/docs/html/training/graphics/opengl/draw.jd b/docs/html/training/graphics/opengl/draw.jd
index ba00627..a588066 100644
--- a/docs/html/training/graphics/opengl/draw.jd
+++ b/docs/html/training/graphics/opengl/draw.jd
@@ -50,13 +50,21 @@
 for memory and processing efficiency.</p>
 
 <pre>
-public void onSurfaceCreated(GL10 unused, EGLConfig config) {
-    ...
+public class MyGLRenderer implements GLSurfaceView.Renderer {
 
-    // initialize a triangle
-    mTriangle = new Triangle();
-    // initialize a square
-    mSquare = new Square();
+    ...
+    private Triangle mTriangle;
+    private Square   mSquare;
+
+    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
+        ...
+
+        // initialize a triangle
+        mTriangle = new Triangle();
+        // initialize a square
+        mSquare = new Square();
+    }
+    ...
 }
 </pre>
 
@@ -77,21 +85,27 @@
 
 <p>You need at least one vertex shader to draw a shape and one fragment shader to color that shape.
 These shaders must be complied and then added to an OpenGL ES program, which is then used to draw
-the shape. Here is an example of how to define basic shaders you can use to draw a shape:</p>
+the shape. Here is an example of how to define basic shaders you can use to draw a shape in the
+<code>Triangle</code> class:</p>
 
 <pre>
-private final String vertexShaderCode =
-    "attribute vec4 vPosition;" +
-    "void main() {" +
-    "  gl_Position = vPosition;" +
-    "}";
+public class Triangle {
 
-private final String fragmentShaderCode =
-    "precision mediump float;" +
-    "uniform vec4 vColor;" +
-    "void main() {" +
-    "  gl_FragColor = vColor;" +
-    "}";
+    private final String vertexShaderCode =
+        "attribute vec4 vPosition;" +
+        "void main() {" +
+        "  gl_Position = vPosition;" +
+        "}";
+
+    private final String fragmentShaderCode =
+        "precision mediump float;" +
+        "uniform vec4 vColor;" +
+        "void main() {" +
+        "  gl_FragColor = vColor;" +
+        "}";
+
+    ...
+}
 </pre>
 
 <p>Shaders contain OpenGL Shading Language (GLSL) code that must be compiled prior to using it in
@@ -125,13 +139,28 @@
 public class Triangle() {
     ...
 
-    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
-    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+    private final int mProgram;
 
-    mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
-    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
-    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
-    GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables
+    public Triangle() {
+        ...
+
+        int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
+                                        vertexShaderCode);
+        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
+                                        fragmentShaderCode);
+
+        // create empty OpenGL ES Program
+        mProgram = GLES20.glCreateProgram();
+
+        // add the vertex shader to program
+        GLES20.glAttachShader(mProgram, vertexShader);
+
+        // add the fragment shader to program
+        GLES20.glAttachShader(mProgram, fragmentShader);
+
+        // creates OpenGL ES program executables
+        GLES20.glLinkProgram(mProgram);
+    }
 }
 </pre>
 
@@ -145,6 +174,12 @@
 function.</p>
 
 <pre>
+private int mPositionHandle;
+private int mColorHandle;
+
+private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
+private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
+
 public void draw() {
     // Add program to OpenGL ES environment
     GLES20.glUseProgram(mProgram);
@@ -176,8 +211,17 @@
 
 <p>Once you have all this code in place, drawing this object just requires a call to the
 {@code draw()} method from within your renderer’s {@link
-android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} method. When you run the
-application, it should look something like this:</p>
+android.opengl.GLSurfaceView.Renderer#onDrawFrame onDrawFrame()} method:
+
+<pre>
+public void onDrawFrame(GL10 unused) {
+    ...
+
+    mTriangle.draw();
+}
+</pre>
+
+<p>When you run the application, it should look something like this:</p>
 
 <img src="{@docRoot}images/opengl/ogl-triangle.png">
 <p class="img-caption">
diff --git a/docs/html/training/graphics/opengl/environment.jd b/docs/html/training/graphics/opengl/environment.jd
index 6b00c76..cf2b64a 100644
--- a/docs/html/training/graphics/opengl/environment.jd
+++ b/docs/html/training/graphics/opengl/environment.jd
@@ -129,28 +129,22 @@
 <pre>
 class MyGLSurfaceView extends GLSurfaceView {
 
+    private final MyGLRenderer mRenderer;
+
     public MyGLSurfaceView(Context context){
         super(context);
 
+        // Create an OpenGL ES 2.0 context
+        setEGLContextClientVersion(2);
+
+        mRenderer = new MyGLRenderer();
+
         // Set the Renderer for drawing on the GLSurfaceView
-        setRenderer(new MyRenderer());
+        setRenderer(mRenderer);
     }
 }
 </pre>
 
-<p>When using OpenGL ES 2.0, you must add another call to your {@link android.opengl.GLSurfaceView}
-constructor, specifying that you want to use the 2.0 API:</p>
-
-<pre>
-// Create an OpenGL ES 2.0 context
-setEGLContextClientVersion(2);
-</pre>
-
-<p class="note"><strong>Note:</strong> If you are using the OpenGL ES 2.0 API, make sure you declare
-this in your application manifest. For more information, see <a href="#manifest">Declare OpenGL ES
-Use
-in the Manifest</a>.</p>
-
 <p>One other optional addition to your {@link android.opengl.GLSurfaceView} implementation is to set
 the render mode to only draw the view when there is a change to your drawing data using the
 {@link android.opengl.GLSurfaceView#RENDERMODE_WHEN_DIRTY GLSurfaceView.RENDERMODE_WHEN_DIRTY}
@@ -186,7 +180,7 @@
 </ul>
 
 <p>Here is a very basic implementation of an OpenGL ES renderer, that does nothing more than draw a
-gray background in the {@link android.opengl.GLSurfaceView}:</p>
+black background in the {@link android.opengl.GLSurfaceView}:</p>
 
 <pre>
 public class MyGLRenderer implements GLSurfaceView.Renderer {
@@ -208,7 +202,7 @@
 </pre>
 
 <p>That’s all there is to it! The code examples above create a simple Android application that
-displays a gray screen using OpenGL. While this code does not do anything very interesting, by
+displays a black screen using OpenGL. While this code does not do anything very interesting, by
 creating these classes, you have laid the foundation you need to start drawing graphic elements with
 OpenGL.</p>
 
diff --git a/docs/html/training/graphics/opengl/motion.jd b/docs/html/training/graphics/opengl/motion.jd
index fbcdd7f..b026a4a 100644
--- a/docs/html/training/graphics/opengl/motion.jd
+++ b/docs/html/training/graphics/opengl/motion.jd
@@ -45,16 +45,17 @@
 
 <h2 id="rotate">Rotate a Shape</h2>
 
-<p>Rotating a drawing object with OpenGL ES 2.0 is relatively simple. You create another
-transformation matrix (a rotation matrix) and then combine it with your projection and
+<p>Rotating a drawing object with OpenGL ES 2.0 is relatively simple. In your renderer, create
+another transformation matrix (a rotation matrix) and then combine it with your projection and
 camera view transformation matrices:</p>
 
 <pre>
 private float[] mRotationMatrix = new float[16];
 public void onDrawFrame(GL10 gl) {
-    ...
     float[] scratch = new float[16];
 
+    ...
+
     // Create a rotation transformation for the triangle
     long time = SystemClock.uptimeMillis() % 4000L;
     float angle = 0.090f * ((int) time);
diff --git a/docs/html/training/graphics/opengl/projection.jd b/docs/html/training/graphics/opengl/projection.jd
index b09e74c..356d5d4 100644
--- a/docs/html/training/graphics/opengl/projection.jd
+++ b/docs/html/training/graphics/opengl/projection.jd
@@ -71,6 +71,11 @@
 android.opengl.Matrix#frustumM Matrix.frustumM()} method:</p>
 
 <pre>
+// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
+private final float[] mMVPMatrix = new float[16];
+private final float[] mProjectionMatrix = new float[16];
+private final float[] mViewMatrix = new float[16];
+
 &#64;Override
 public void onSurfaceChanged(GL10 unused, int width, int height) {
     GLES20.glViewport(0, 0, width, height);
@@ -95,10 +100,10 @@
 <h2 id="camera-view">Define a Camera View</h2>
 
 <p>Complete the process of transforming your drawn objects by adding a camera view transformation as
-part of the drawing process. In the following example code, the camera view transformation is
-calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()} method and then
-combined with the previously calculated projection matrix. The combined transformation matrices
-are then passed to the drawn shape.</p>
+part of the drawing process in your renderer. In the following example code, the camera view
+transformation is calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()}
+method and then combined with the previously calculated projection matrix. The combined
+transformation matrices are then passed to the drawn shape.</p>
 
 <pre>
 &#64;Override
@@ -119,7 +124,32 @@
 <h2 id="#transform">Apply Projection and Camera Transformations</h2>
 
 <p>In order to use the combined projection and camera view transformation matrix shown in the
-previews sections, modify the {@code draw()} method of your graphic objects to accept the combined
+previews sections, first add a matrix variable to the <em>vertex shader</em> previously defined
+in the <code>Triangle</code> class:</p>
+
+<pre>
+public class Triangle {
+
+    private final String vertexShaderCode =
+        // This matrix member variable provides a hook to manipulate
+        // the coordinates of the objects that use this vertex shader
+        <strong>"uniform mat4 uMVPMatrix;" +</strong>
+        "attribute vec4 vPosition;" +
+        "void main() {" +
+        // the matrix must be included as a modifier of gl_Position
+        // Note that the uMVPMatrix factor *must be first* in order
+        // for the matrix multiplication product to be correct.
+        "  gl_Position = <strong>uMVPMatrix</strong> * vPosition;" +
+        "}";
+
+    // Use to access and set the view transformation
+    private int mMVPMatrixHandle;
+
+    ...
+}
+</pre>
+
+<p>Next, modify the {@code draw()} method of your graphic objects to accept the combined
 transformation matrix and apply it to the shape:</p>
 
 <pre>
@@ -127,14 +157,16 @@
     ...
 
     // get handle to shape's transformation matrix
-    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+    <strong>mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");</strong>
 
     // Pass the projection and view transformation to the shader
-    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
+    <strong>GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);</strong>
 
     // Draw the triangle
     GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
-    ...
+
+    // Disable vertex array
+    GLES20.glDisableVertexAttribArray(mPositionHandle);
 }
 </pre>
 
diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
index 4c9f0c7..089ede7 100644
--- a/docs/html/training/graphics/opengl/touch.jd
+++ b/docs/html/training/graphics/opengl/touch.jd
@@ -50,6 +50,10 @@
 an angle of rotation for a shape.</p>
 
 <pre>
+private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
+private float mPreviousX;
+private float mPreviousY;
+
 &#64;Override
 public boolean onTouchEvent(MotionEvent e) {
     // MotionEvent reports input details from the touch screen
@@ -77,7 +81,7 @@
 
             mRenderer.setAngle(
                     mRenderer.getAngle() +
-                    ((dx + dy) * TOUCH_SCALE_FACTOR);  // = 180.0f / 320
+                    ((dx + dy) * TOUCH_SCALE_FACTOR));
             requestRender();
     }
 
@@ -108,12 +112,22 @@
 <p>The example code above requires that you expose the rotation angle through your renderer by
 adding a public member. Since the renderer code is running on a separate thread from the main user
 interface thread of your application, you must declare this public variable as {@code volatile}.
-Here is the code to do that:</p>
+Here is the code to declare the variable and expose the getter and setter pair:</p>
 
 <pre>
 public class MyGLRenderer implements GLSurfaceView.Renderer {
     ...
+
     public volatile float mAngle;
+
+    public float getAngle() {
+        return mAngle;
+    }
+
+    public void setAngle(float angle) {
+        mAngle = angle;
+    }
+}
 </pre>
 
 
diff --git a/docs/html/training/material/drawables.jd b/docs/html/training/material/drawables.jd
index 820a004..a2de8e9 100644
--- a/docs/html/training/material/drawables.jd
+++ b/docs/html/training/material/drawables.jd
@@ -73,7 +73,7 @@
 <pre>
 dependencies {
     ...
-    compile 'com.android.support:palette-v7:21.0.+'
+    compile 'com.android.support:palette-v7:21.0.0'
 }
 </pre>
 
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index f5999a5..c59d8ff 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -951,6 +951,10 @@
               Creating a Catalog Browser</a>
           </li>
           <li>
+            <a href="<?cs var:toroot ?>training/tv/playback/card.html">
+              Providing a Card View</a>
+          </li>
+          <li>
             <a href="<?cs var:toroot ?>training/tv/playback/details.html"
                ja-lang="詳細ビューをビルドする">
               Building a Details View</a>
@@ -1883,4 +1887,4 @@
     buildToggleLists();
     changeNavLang(getLangPref());
 //-->
-</script>
+</script>
\ No newline at end of file
diff --git a/docs/html/training/tv/playback/card.jd b/docs/html/training/tv/playback/card.jd
new file mode 100644
index 0000000..8ac75fd
--- /dev/null
+++ b/docs/html/training/tv/playback/card.jd
@@ -0,0 +1,156 @@
+page.title=Providing a Card View
+page.tags="card"
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#presenter">Create a Card Presenter</a></li>
+    <li><a href="#card-view">Create a Card View</a></li>
+  </ol>
+  <h2>Try it out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
+    Leanback sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>In the previous lesson, you created a catalog browser, implemented in a browse fragment, that
+displays a list of media items. In this lesson, you create the card views for your media items and
+present them in the browse fragment.</p>
+
+<p>The {@link android.support.v17.leanback.widget.BaseCardView} class and subclasses display the meta
+data associated with a media item. The {@link android.support.v17.leanback.widget.ImageCardView}
+class used in this lesson displays an image for the content along with the media item's title.</p>
+
+<p>This lesson describes code from the <a href="https://github.com/googlesamples/androidtv-Leanback">
+Android Leanback sample app</a>, available on GitHub. Use this sample code to start your own
+app.</p>
+
+<img itemprop="image" src="{@docRoot}images/tv/app-browse.png" alt="App main screen"/>
+<p class="img-caption"><b>Figure 1.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
+Leanback sample app</a> browse fragment with a card presenter displaying card view objects.</p>
+
+<h2 id="presenter">Create a Card Presenter</h2>
+
+<p>A {@link android.support.v17.leanback.widget.Presenter} generates views and binds objects to them
+on demand. In the browse fragment where your app presents its content to the user, you create a
+{@link android.support.v17.leanback.widget.Presenter} for the content cards and pass it to the adapter
+that adds the content to the screen. In the following code, the <code>CardPresenter</code> is created
+in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader, java.lang.Object) onLoadFinished()}
+callback of the {@link android.support.v4.app.LoaderManager}.</p>
+
+<pre>
+&#64;Override
+public void onLoadFinished(Loader&lt;HashMap&lt;String, List&lt;Movie&gt;&gt;&gt; arg0,
+                           HashMap&lt;String, List&lt;Movie&gt;&gt; data) {
+
+    mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
+    CardPresenter cardPresenter = new CardPresenter();
+
+    int i = 0;
+
+    for (Map.Entry&lt;String, List&lt;Movie&gt;&gt; entry : data.entrySet()) {
+        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+        List&lt;Movie&gt; list = entry.getValue();
+
+        for (int j = 0; j &lt; list.size(); j++) {
+            listRowAdapter.add(list.get(j));
+        }
+        HeaderItem header = new HeaderItem(i, entry.getKey(), null);
+        i++;
+        mRowsAdapter.add(new ListRow(header, listRowAdapter));
+    }
+
+    HeaderItem gridHeader = new HeaderItem(i, getString(R.string.more_samples),
+            null);
+
+    GridItemPresenter gridPresenter = new GridItemPresenter();
+    ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter);
+    gridRowAdapter.add(getString(R.string.grid_view));
+    gridRowAdapter.add(getString(R.string.error_fragment));
+    gridRowAdapter.add(getString(R.string.personal_settings));
+    mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
+
+    setAdapter(mRowsAdapter);
+
+    updateRecommendations();
+}
+</pre>
+
+<h2 id="card-view">Create a Card View</h2>
+
+<p>In this step, you build the card presenter with a view holder for the card view that describes
+your media content items. Note that each presenter must only create one view type. If you have two
+different card view types then you need two different card presenters.</p>
+
+<p>In the {@link android.support.v17.leanback.widget.Presenter}, implement an
+{@link android.support.v17.leanback.widget.Presenter#onCreateViewHolder(android.view.ViewGroup) onCreateViewHolder()}
+callback that creates a view holder that can be used to display a content item.</p>
+
+<pre>
+&#64;Override
+public class CardPresenter extends Presenter {
+
+    private Context mContext;
+    private static int CARD_WIDTH = 313;
+    private static int CARD_HEIGHT = 176;
+    private Drawable mDefaultCardImage;
+
+    &#64;Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        mContext = parent.getContext();
+        mDefaultCardImage = mContext.getResources().getDrawable(R.drawable.movie);
+...
+</pre>
+
+<p>In the {@link android.support.v17.leanback.widget.Presenter#onCreateViewHolder(android.view.ViewGroup)
+onCreateViewHolder()} method, create a card view for content items. The sample below uses an
+{@link android.support.v17.leanback.widget.ImageCardView}.</p>
+
+<p>When a card is selected, the default behavior expands it to a larger size. If you want to designate
+a different color for the selected card, call {@link android.support.v17.leanback.widget.BaseCardView#setSelected(boolean)
+setSelected()}
+as shown here.</p>
+
+<pre>
+...
+    ImageCardView cardView = new ImageCardView(mContext) {
+        &#64;Override
+        public void setSelected(boolean selected) {
+            int selected_background = mContext.getResources().getColor(R.color.detail_background);
+            int default_background = mContext.getResources().getColor(R.color.default_background);
+            int color = selected ? selected_background : default_background;
+            findViewById(R.id.info_field).setBackgroundColor(color);
+            super.setSelected(selected);
+        }
+    };
+...
+</pre>
+
+<p>When the user opens your app, the {@link android.support.v17.leanback.widget.Presenter.ViewHolder}
+displays the <code>CardView</code> objects for your content items. You need to set these to receive
+focus from the D-pad controller by calling {@link android.view.View#setFocusable(boolean) setFocusable(true)}
+and {@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode(true)}.</p>
+
+<pre>
+...
+    cardView.setFocusable(true);
+    cardView.setFocusableInTouchMode(true);
+    return new ViewHolder(cardView);
+}
+</pre>
+
+<p>When the user selects the {@link android.support.v17.leanback.widget.ImageCardView}, it expands
+to reveal its text area with the background color you specify, as shown in figure 2.</p>
+
+<img itemprop="image" src="{@docRoot}images/tv/card-view.png" alt="App card view"/>
+<p class="img-caption"><b>Figure 2.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
+Leanback sample app</a> image card view when selected.</p>
+
+
diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd
index 5427d48..0e9c5ec 100644
--- a/docs/html/training/tv/playback/index.jd
+++ b/docs/html/training/tv/playback/index.jd
@@ -56,6 +56,9 @@
     <dd>Learn how to use the Leanback support library to build a browsing interface for media
       catalogs.</dd>
 
+  <dt><b><a href="details.html">Providing a Card View</a></b></dt>
+    <dd>Learn how to use the Leanback support library to build a card view for content items.</dd>
+
   <dt><b><a href="details.html">Building a Details View</a></b></dt>
     <dd>Learn how to use the Leanback support library to build a details page for media items.</dd>
 
diff --git a/docs/html/training/tv/start/layouts.jd b/docs/html/training/tv/start/layouts.jd
index 177ea7a..a378096 100644
--- a/docs/html/training/tv/start/layouts.jd
+++ b/docs/html/training/tv/start/layouts.jd
@@ -119,8 +119,8 @@
 
 <p>
   Avoid screen elements being clipped due to overscan and by incorporating a 10% margin
-  on all sides of your layout. This translates into a 27dp margin on the left and right edges and
-  a 48dp margin on the top and bottom of your base layouts for activities. The following
+  on all sides of your layout. This translates into a 48dp margin on the left and right edges and
+  a 27dp margin on the top and bottom of your base layouts for activities. The following
   example layout demonstrates how to set these margins in the root layout for a TV app:
 </p>
 
diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd
index c7affd1..453c30e 100644
--- a/docs/html/training/wearables/watch-faces/index.jd
+++ b/docs/html/training/wearables/watch-faces/index.jd
@@ -21,6 +21,14 @@
   </div>
 </a>
 
+<a class="notice-developers-video wide"
+    href="https://www.youtube.com/watch?v=AK38PJZmIW8">
+<div>
+    <h3>Video</h3>
+    <p>DevBytes: Watch Faces for Android Wear</p>
+</div>
+</a>
+
 <p>Watch faces in Android Wear leverage a dynamic digital canvas to tell time using colors,
 animations, and relevant contextual information. The <a
 href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java
index 206c959..48ee6fa 100644
--- a/graphics/java/android/graphics/AvoidXfermode.java
+++ b/graphics/java/android/graphics/AvoidXfermode.java
@@ -23,7 +23,7 @@
 @Deprecated
 public class AvoidXfermode extends Xfermode {
 
-    // these need to match the enum in SkAvoidXfermode.h on the native side
+    // these need to match the enum in AvoidXfermode.h on the native side
     public enum Mode {
         AVOID   (0),    //!< draw everywhere except on the opColor
         TARGET  (1);    //!< draw only on top of the opColor
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index fa9af2a..39272b9 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -122,11 +122,6 @@
      * @param canvas  The picture is drawn to this canvas
      */
     public void draw(Canvas canvas) {
-        if (canvas.isHardwareAccelerated()) {
-            throw new IllegalArgumentException(
-                    "Picture playback is only supported on software canvas.");
-        }
-
         if (mRecordingCanvas != null) {
             endRecording();
         }
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 8b70a08..50a6df4 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -34,7 +34,6 @@
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 
@@ -60,28 +59,49 @@
 public class InsetDrawable extends Drawable implements Drawable.Callback {
     private final Rect mTmpRect = new Rect();
 
-    private final InsetState mState;
+    private InsetState mState;
+    private Drawable mDrawable;
 
     private boolean mMutated;
 
-    /*package*/ InsetDrawable() {
-        this(null, null);
+    /**
+     * No-arg constructor used by drawable inflation.
+     */
+    InsetDrawable() {
+        this(new InsetState(), null);
     }
 
+    /**
+     * Creates a new inset drawable with the specified inset.
+     *
+     * @param drawable The drawable to inset.
+     * @param inset Inset in pixels around the drawable.
+     */
     public InsetDrawable(Drawable drawable, int inset) {
         this(drawable, inset, inset, inset, inset);
     }
 
-    public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
-                         int insetRight, int insetBottom) {
-        this(null, null);
+    /**
+     * Creates a new inset drawable with the specified insets.
+     *
+     * @param drawable The drawable to inset.
+     * @param insetLeft Left inset in pixels.
+     * @param insetTop Top inset in pixels.
+     * @param insetRight Right inset in pixels.
+     * @param insetBottom Bottom inset in pixels.
+     */
+    public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
+            int insetBottom) {
+        this(new InsetState(), null);
 
-        mState.mDrawable = drawable;
+        mState.mDrawableState = drawable == null ? null : drawable.getConstantState();
         mState.mInsetLeft = insetLeft;
         mState.mInsetTop = insetTop;
         mState.mInsetRight = insetRight;
         mState.mInsetBottom = insetBottom;
 
+        mDrawable = drawable;
+
         if (drawable != null) {
             drawable.setCallback(this);
         }
@@ -93,38 +113,53 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
 
-        // Reset mDrawable to preserve old multiple-inflate behavior. This is
-        // silly, but we have CTS tests that rely on it.
-        mState.mDrawable = null;
-
         updateStateFromTypedArray(a);
         inflateChildElements(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
+    private void setDrawable(Drawable dr) {
+        if (mDrawable != null) {
+            mDrawable.setCallback(null);
+        }
+
+        mDrawable = dr;
+
+        if (dr != null) {
+            dr.setCallback(this);
+            dr.setVisible(isVisible(), true);
+            dr.setState(getState());
+            dr.setLevel(getLevel());
+            dr.setBounds(getBounds());
+            dr.setLayoutDirection(getLayoutDirection());
+        }
+    }
+
     private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         // Load inner XML elements.
-        if (mState.mDrawable == null) {
+        if (mDrawable == null) {
             int type;
             while ((type=parser.next()) == XmlPullParser.TEXT) {
             }
             if (type != XmlPullParser.START_TAG) {
-                throw new XmlPullParserException(
-                        parser.getPositionDescription()
-                                + ": <inset> tag requires a 'drawable' attribute or "
-                                + "child tag defining a drawable");
+                throw new XmlPullParserException(parser.getPositionDescription()
+                        + ": <inset> tag requires a 'drawable' attribute or "
+                        + "child tag defining a drawable");
             }
+
             final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            mState.mDrawable = dr;
-            dr.setCallback(this);
+            if (dr != null) {
+                mState.mDrawableState = dr.getConstantState();
+                setDrawable(dr);
+            }
         }
     }
 
     private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
-        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+        if (mDrawable == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <inset> tag requires a 'drawable' attribute or "
@@ -148,8 +183,8 @@
                 case R.styleable.InsetDrawable_drawable:
                     final Drawable dr = a.getDrawable(attr);
                     if (dr != null) {
-                        state.mDrawable = dr;
-                        dr.setCallback(this);
+                        mState.mDrawableState = dr.getConstantState();
+                        setDrawable(dr);
                     }
                     break;
                 case R.styleable.InsetDrawable_inset:
@@ -198,8 +233,8 @@
             }
         }
 
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
+        if (mDrawable != null && mDrawable.canApplyTheme()) {
+            mDrawable.applyTheme(t);
         }
     }
 
@@ -234,27 +269,27 @@
 
     @Override
     public void draw(Canvas canvas) {
-        mState.mDrawable.draw(canvas);
+        mDrawable.draw(canvas);
     }
 
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
                 | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
+                | mDrawable.getChangingConfigurations();
     }
 
     @Override
     public boolean getPadding(Rect padding) {
-        boolean pad = mState.mDrawable.getPadding(padding);
+        final boolean pad = mDrawable.getPadding(padding);
 
         padding.left += mState.mInsetLeft;
         padding.right += mState.mInsetRight;
         padding.top += mState.mInsetTop;
         padding.bottom += mState.mInsetBottom;
 
-        return pad || (mState.mInsetLeft | mState.mInsetRight |
-                mState.mInsetTop | mState.mInsetBottom) != 0;
+        return pad || (mState.mInsetLeft | mState.mInsetRight
+                | mState.mInsetTop | mState.mInsetBottom) != 0;
     }
 
     /** @hide */
@@ -269,61 +304,61 @@
 
     @Override
     public void setHotspot(float x, float y) {
-        mState.mDrawable.setHotspot(x, y);
+        mDrawable.setHotspot(x, y);
     }
 
     @Override
     public void setHotspotBounds(int left, int top, int right, int bottom) {
-        mState.mDrawable.setHotspotBounds(left, top, right, bottom);
+        mDrawable.setHotspotBounds(left, top, right, bottom);
     }
 
     /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
-        mState.mDrawable.getHotspotBounds(outRect);
+        mDrawable.getHotspotBounds(outRect);
     }
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
+        mDrawable.setVisible(visible, restart);
         return super.setVisible(visible, restart);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
+        mDrawable.setAlpha(alpha);
     }
 
     @Override
     public int getAlpha() {
-        return mState.mDrawable.getAlpha();
+        return mDrawable.getAlpha();
     }
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
+        mDrawable.setColorFilter(cf);
     }
 
     @Override
     public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
+        mDrawable.setTintList(tint);
     }
 
     @Override
     public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
+        mDrawable.setTintMode(tintMode);
     }
 
     /** {@hide} */
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        mState.mDrawable.setLayoutDirection(layoutDirection);
+        mDrawable.setLayoutDirection(layoutDirection);
     }
 
     @Override
     public int getOpacity() {
         final InsetState state = mState;
-        final int opacity = state.mDrawable.getOpacity();
+        final int opacity = mDrawable.getOpacity();
         if (opacity == PixelFormat.OPAQUE && (state.mInsetLeft > 0 || state.mInsetTop > 0
                 || state.mInsetRight > 0 || state.mInsetBottom > 0)) {
             return PixelFormat.TRANSLUCENT;
@@ -333,19 +368,19 @@
 
     @Override
     public boolean isStateful() {
-        return mState.mDrawable.isStateful();
+        return mDrawable.isStateful();
     }
 
     @Override
     protected boolean onStateChange(int[] state) {
-        boolean changed = mState.mDrawable.setState(state);
+        final boolean changed = mDrawable.setState(state);
         onBoundsChange(getBounds());
         return changed;
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        return mState.mDrawable.setLevel(level);
+        return mDrawable.setLevel(level);
     }
 
     @Override
@@ -358,24 +393,22 @@
         r.right -= mState.mInsetRight;
         r.bottom -= mState.mInsetBottom;
 
-        mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+        mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth()
-                + mState.mInsetLeft + mState.mInsetRight;
+        return mDrawable.getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight()
-                + mState.mInsetTop + mState.mInsetBottom;
+        return mDrawable.getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;
     }
 
     @Override
     public void getOutline(@NonNull Outline outline) {
-        mState.mDrawable.getOutline(outline);
+        mDrawable.getOutline(outline);
     }
 
     @Override
@@ -390,7 +423,9 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
+            mState = new InsetState(mState);
+            mDrawable.mutate();
+            mState.mDrawableState = mDrawable.getConstantState();
             mMutated = true;
         }
         return this;
@@ -401,7 +436,7 @@
      */
     public void clearMutated() {
         super.clearMutated();
-        mState.mDrawable.clearMutated();
+        mDrawable.clearMutated();
         mMutated = false;
     }
 
@@ -409,51 +444,53 @@
      * Returns the drawable wrapped by this InsetDrawable. May be null.
      */
     public Drawable getDrawable() {
-        return mState.mDrawable;
+        return mDrawable;
     }
 
-    final static class InsetState extends ConstantState {
+    private static final class InsetState extends ConstantState {
         int[] mThemeAttrs;
         int mChangingConfigurations;
 
-        Drawable mDrawable;
+        ConstantState mDrawableState;
 
         int mInsetLeft = 0;
         int mInsetTop = 0;
         int mInsetRight = 0;
         int mInsetBottom = 0;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        public InsetState() {
+            // Empty constructor.
+        }
 
-        InsetState(InsetState orig, InsetDrawable owner, Resources res) {
+        public InsetState(InsetState orig) {
             if (orig != null) {
                 mThemeAttrs = orig.mThemeAttrs;
                 mChangingConfigurations = orig.mChangingConfigurations;
-                if (res != null) {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
-                } else {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
-                }
-                mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-                mDrawable.setBounds(orig.mDrawable.getBounds());
-                mDrawable.setLevel(orig.mDrawable.getLevel());
+                mDrawableState = orig.mDrawableState;
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
                 mInsetRight = orig.mInsetRight;
                 mInsetBottom = orig.mInsetBottom;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+            return mThemeAttrs != null
+                    || (mDrawableState != null && mDrawableState.canApplyTheme())
                     || super.canApplyTheme();
         }
 
         @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final ConstantState state = mDrawableState;
+            if (state != null) {
+                return state.addAtlasableBitmaps(atlasList);
+            }
+            return 0;
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new InsetDrawable(this, null);
         }
@@ -468,27 +505,31 @@
             return mChangingConfigurations;
         }
 
-        boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
-
-        @Override
-        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
-            final ConstantState state = mDrawable.getConstantState();
-            if (state != null) {
-                return state.addAtlasableBitmaps(atlasList);
-            }
-            return 0;
+        public boolean canConstantState() {
+            return mDrawableState != null;
         }
     }
 
+    /**
+     * The one constructor to rule them all. This is called by all public
+     * constructors to set the state and initialize local properties.
+     */
     private InsetDrawable(InsetState state, Resources res) {
-        mState = new InsetState(state, this, res);
+        mState = state;
+
+        updateLocalState(res);
+    }
+
+    /**
+     * Initializes local dynamic properties from state. This should be called
+     * after significant state changes, e.g. from the One True Constructor and
+     * after inflating or applying a theme.
+     */
+    private void updateLocalState(Resources res) {
+        if (mState.mDrawableState != null) {
+            final Drawable dr = mState.mDrawableState.newDrawable(res);
+            setDrawable(dr);
+        }
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index daf4427..616aebd 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -29,6 +29,8 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.LayoutDirection;
+import android.view.Gravity;
 import android.view.View;
 
 import com.android.internal.R;
@@ -54,6 +56,11 @@
  * @attr ref android.R.styleable#LayerDrawableItem_top
  * @attr ref android.R.styleable#LayerDrawableItem_right
  * @attr ref android.R.styleable#LayerDrawableItem_bottom
+ * @attr ref android.R.styleable#LayerDrawableItem_start
+ * @attr ref android.R.styleable#LayerDrawableItem_end
+ * @attr ref android.R.styleable#LayerDrawableItem_width
+ * @attr ref android.R.styleable#LayerDrawableItem_height
+ * @attr ref android.R.styleable#LayerDrawableItem_gravity
  * @attr ref android.R.styleable#LayerDrawableItem_drawable
  * @attr ref android.R.styleable#LayerDrawableItem_id
 */
@@ -73,6 +80,9 @@
      */
     public static final int PADDING_MODE_STACK = 1;
 
+    /** Value used for undefined start and end insets. */
+    private static final int UNDEFINED_INSET = Integer.MIN_VALUE;
+
     LayerState mLayerState;
 
     private int mOpacityOverride = PixelFormat.UNKNOWN;
@@ -82,6 +92,8 @@
     private int[] mPaddingB;
 
     private final Rect mTmpRect = new Rect();
+    private final Rect mTmpOutRect = new Rect();
+    private final Rect mTmpContainer = new Rect();
     private Rect mHotspotBounds;
     private boolean mMutated;
 
@@ -231,6 +243,16 @@
                 R.styleable.LayerDrawableItem_right, layer.mInsetR);
         layer.mInsetB = a.getDimensionPixelOffset(
                 R.styleable.LayerDrawableItem_bottom, layer.mInsetB);
+        layer.mInsetS = a.getDimensionPixelOffset(
+                R.styleable.LayerDrawableItem_start, layer.mInsetS);
+        layer.mInsetE = a.getDimensionPixelOffset(
+                R.styleable.LayerDrawableItem_end, layer.mInsetE);
+        layer.mWidth = a.getDimensionPixelSize(
+                R.styleable.LayerDrawableItem_width, layer.mWidth);
+        layer.mHeight = a.getDimensionPixelSize(
+                R.styleable.LayerDrawableItem_height, layer.mHeight);
+        layer.mGravity = a.getInteger(
+                R.styleable.LayerDrawableItem_gravity, layer.mGravity);
         layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId);
 
         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
@@ -300,7 +322,13 @@
         return false;
     }
 
-    void addLayer(ChildDrawable layer) {
+    /**
+     * Adds a new layer at the end of list of layers and returns its index.
+     *
+     * @param layer The layer to add.
+     * @return The index of the layer.
+     */
+    int addLayer(ChildDrawable layer) {
         final LayerState st = mLayerState;
         final int N = st.mChildren != null ? st.mChildren.length : 0;
         final int i = st.mNum;
@@ -316,12 +344,13 @@
         st.mChildren[i] = layer;
         st.mNum++;
         st.invalidateCache();
+        return i;
     }
 
     /**
      * Add a new layer to this drawable. The new layer is identified by an id.
      *
-     * @param layer The drawable to add as a layer.
+     * @param dr The drawable to add as a layer.
      * @param themeAttrs Theme attributes extracted from the layer.
      * @param id The id of the new layer.
      * @param left The left padding of the new layer.
@@ -329,12 +358,11 @@
      * @param right The right padding of the new layer.
      * @param bottom The bottom padding of the new layer.
      */
-    ChildDrawable addLayer(Drawable layer, int[] themeAttrs, int id, int left, int top, int right,
-            int bottom) {
-        final ChildDrawable childDrawable = new ChildDrawable();
+    ChildDrawable addLayer(Drawable dr, int[] themeAttrs, int id,
+            int left, int top, int right, int bottom) {
+        final ChildDrawable childDrawable = createLayer(dr);
         childDrawable.mId = id;
         childDrawable.mThemeAttrs = themeAttrs;
-        childDrawable.mDrawable = layer;
         childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
         childDrawable.mInsetL = left;
         childDrawable.mInsetT = top;
@@ -343,12 +371,31 @@
 
         addLayer(childDrawable);
 
-        mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations();
-        layer.setCallback(this);
+        mLayerState.mChildrenChangingConfigurations |= dr.getChangingConfigurations();
+        dr.setCallback(this);
 
         return childDrawable;
     }
 
+    private ChildDrawable createLayer(Drawable dr) {
+        final ChildDrawable layer = new ChildDrawable();
+        layer.mDrawable = dr;
+        return layer;
+    }
+
+    /**
+     * Adds a new layer containing the specified {@code drawable} to the end of
+     * the layer list and returns its index.
+     *
+     * @param dr The drawable to add as a new layer.
+     * @return The index of the new layer.
+     */
+    public int addLayer(Drawable dr) {
+        final ChildDrawable layer = createLayer(dr);
+        final int index = addLayer(layer);
+        return index;
+    }
+
     /**
      * Looks for a layer with the given ID and returns its {@link Drawable}.
      * <p>
@@ -373,15 +420,38 @@
     /**
      * Sets the ID of a layer.
      *
-     * @param index The index of the layer which will received the ID.
-     * @param id The ID to assign to the layer.
+     * @param index The index of the layer to modify, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @param id The id to assign to the layer.
+     *
+     * @see #getId(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_id
      */
     public void setId(int index, int id) {
         mLayerState.mChildren[index].mId = id;
     }
 
     /**
-     * Returns the number of layers contained within this.
+     * Returns the ID of the specified layer.
+     *
+     * @param index The index of the layer, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @return The id of the layer or {@link android.view.View#NO_ID} if the
+     *         layer has no id.
+     *
+     * @see #setId(int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_id
+     */
+    public int getId(int index) {
+        if (index >= mLayerState.mNum) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mLayerState.mChildren[index].mId;
+    }
+
+    /**
+     * Returns the number of layers contained within this layer drawable.
+     *
      * @return The number of layers.
      */
     public int getNumberOfLayers() {
@@ -389,29 +459,7 @@
     }
 
     /**
-     * Returns the drawable at the specified layer index.
-     *
-     * @param index The layer index of the drawable to retrieve.
-     *
-     * @return The {@link android.graphics.drawable.Drawable} at the specified layer index.
-     */
-    public Drawable getDrawable(int index) {
-        return mLayerState.mChildren[index].mDrawable;
-    }
-
-    /**
-     * Returns the id of the specified layer.
-     *
-     * @param index The index of the layer.
-     *
-     * @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id.
-     */
-    public int getId(int index) {
-        return mLayerState.mChildren[index].mId;
-    }
-
-    /**
-     * Sets (or replaces) the {@link Drawable} for the layer with the given id.
+     * Replaces the {@link Drawable} for the layer with the given id.
      *
      * @param id The layer ID to search for.
      * @param drawable The replacement {@link Drawable}.
@@ -419,31 +467,171 @@
      *         the id was not found).
      */
     public boolean setDrawableByLayerId(int id, Drawable drawable) {
+        final int index = findIndexByLayerId(id);
+        if (index < 0) {
+            return false;
+        }
+
+        setDrawable(index, drawable);
+        return true;
+    }
+
+    /**
+     * Returns the layer with the specified {@code id}.
+     * <p>
+     * If multiple layers have the same ID, returns the layer with the lowest
+     * index.
+     *
+     * @param id The ID of the layer to return.
+     * @return The index of the layer with the specified ID.
+     */
+    public int findIndexByLayerId(int id) {
         final ChildDrawable[] layers = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable childDrawable = layers[i];
             if (childDrawable.mId == id) {
-                if (childDrawable.mDrawable != null) {
-                    if (drawable != null) {
-                        final Rect bounds = childDrawable.mDrawable.getBounds();
-                        drawable.setBounds(bounds);
-                    }
-
-                    childDrawable.mDrawable.setCallback(null);
-                }
-
-                if (drawable != null) {
-                    drawable.setCallback(this);
-                }
-
-                childDrawable.mDrawable = drawable;
-                mLayerState.invalidateCache();
-                return true;
+                return i;
             }
         }
 
-        return false;
+        return -1;
+    }
+
+    /**
+     * Sets the drawable for the layer at the specified index.
+     *
+     * @param index The index of the layer to modify, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @param drawable The drawable to set for the layer.
+     *
+     * @see #getDrawable(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_drawable
+     */
+    public void setDrawable(int index, Drawable drawable) {
+        if (index >= mLayerState.mNum) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        final ChildDrawable[] layers = mLayerState.mChildren;
+        final ChildDrawable childDrawable = layers[index];
+        if (childDrawable.mDrawable != null) {
+            if (drawable != null) {
+                final Rect bounds = childDrawable.mDrawable.getBounds();
+                drawable.setBounds(bounds);
+            }
+
+            childDrawable.mDrawable.setCallback(null);
+        }
+
+        if (drawable != null) {
+            drawable.setCallback(this);
+            drawable.setLayoutDirection(getLayoutDirection());
+            drawable.setLevel(getLevel());
+        }
+
+        childDrawable.mDrawable = drawable;
+        mLayerState.invalidateCache();
+    }
+
+    /**
+     * Returns the drawable for the layer at the specified index.
+     *
+     * @param index The index of the layer, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @return The {@link Drawable} at the specified layer index.
+     *
+     * @see #setDrawable(int, Drawable)
+     * @attr ref android.R.styleable#LayerDrawableItem_drawable
+     */
+    public Drawable getDrawable(int index) {
+        if (index >= mLayerState.mNum) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mLayerState.mChildren[index].mDrawable;
+    }
+
+    /**
+     * Sets an explicit size for the specified layer.
+     * <p>
+     * <strong>Note:</strong> Setting an explicit layer size changes the
+     * default layer gravity behavior. See {@link #setLayerGravity(int, int)}
+     * for more information.
+     *
+     * @param index the index of the drawable to adjust
+     * @param w width in pixels, or -1 to use the intrinsic width
+     * @param h height in pixels, or -1 to use the intrinsic height
+     *
+     * @see #getLayerWidth(int)
+     * @see #getLayerHeight(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public void setLayerSize(int index, int w, int h) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mWidth = w;
+        childDrawable.mHeight = h;
+    }
+
+    /**
+     * @param index the index of the drawable to adjust
+     * @return the explicit width of the layer, or -1 if not specified
+     *
+     * @see #setLayerSize(int, int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     */
+    public int getLayerWidth(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mWidth;
+    }
+
+    /**
+     * @param index the index of the drawable to adjust
+     * @return the explicit height of the layer, or -1 if not specified
+     *
+     * @see #setLayerSize(int, int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public int getLayerHeight(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mHeight;
+    }
+
+    /**
+     * Sets the gravity used to position or stretch the specified layer within
+     * its container. Gravity is applied after any layer insets (see
+     * {@link #setLayerInset(int, int, int, int, int)}) or padding (see
+     * {@link #setPaddingMode(int)}).
+     * <p>
+     * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default
+     * behavior depends on whether an explicit width or height has been set
+     * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set,
+     * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or
+     * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction
+     * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}.
+     *
+     * @param index the index of the drawable to adjust
+     * @param gravity the gravity to set for the layer
+     *
+     * @see #getLayerGravity(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_gravity
+     */
+    public void setLayerGravity(int index, int gravity) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mGravity = gravity;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return the gravity used to position or stretch the specified layer
+     *         within its container
+     *
+     * @see #setLayerGravity(int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_gravity
+     */
+    public int getLayerGravity(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mGravity;
     }
 
     /**
@@ -454,13 +642,43 @@
      * @param t number of pixels to add to the top bound
      * @param r number of pixels to subtract from the right bound
      * @param b number of pixels to subtract from the bottom bound
+     *
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
      */
     public void setLayerInset(int index, int l, int t, int r, int b) {
+        setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET);
+    }
+
+    /**
+     * Specifies the relative insets in pixels for the drawable at the
+     * specified index.
+     *
+     * @param index the index of the drawable to adjust
+     * @param s number of pixels to inset from the start bound
+     * @param t number of pixels to inset from the top bound
+     * @param e number of pixels to inset from the end bound
+     * @param b number of pixels to inset from the bottom bound
+     *
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public void setLayerInsetRelative(int index, int s, int t, int e, int b) {
+        setLayerInsetInternal(index, 0, t, 0, b, s, e);
+    }
+
+    private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) {
         final ChildDrawable childDrawable = mLayerState.mChildren[index];
         childDrawable.mInsetL = l;
         childDrawable.mInsetT = t;
         childDrawable.mInsetR = r;
         childDrawable.mInsetB = b;
+        childDrawable.mInsetS = s;
+        childDrawable.mInsetE = e;
     }
 
     /**
@@ -770,7 +988,7 @@
         }
 
         if (paddingChanged) {
-            onBoundsChange(getBounds());
+            updateLayerBounds(getBounds());
         }
 
         return changed;
@@ -795,7 +1013,7 @@
         }
 
         if (paddingChanged) {
-            onBoundsChange(getBounds());
+            updateLayerBounds(getBounds());
         }
 
         return changed;
@@ -803,18 +1021,51 @@
 
     @Override
     protected void onBoundsChange(Rect bounds) {
+        updateLayerBounds(bounds);
+    }
+
+    private void updateLayerBounds(Rect bounds) {
         int padL = 0;
         int padT = 0;
         int padR = 0;
         int padB = 0;
 
+        final Rect outRect = mTmpOutRect;
+        final int layoutDirection = getLayoutDirection();
         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT,
-                    bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB);
+            final Drawable d = r.mDrawable;
+            final Rect container = mTmpContainer;
+            container.set(d.getBounds());
+
+            // Take the resolved layout direction into account. If start / end
+            // padding are defined, they will be resolved (hence overriding) to
+            // left / right or right / left depending on the resolved layout
+            // direction. If start / end padding are not defined, use the
+            // left / right ones.
+            final int insetL, insetR;
+            if (layoutDirection == LayoutDirection.RTL) {
+                insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE;
+                insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS;
+            } else {
+                insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS;
+                insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE;
+            }
+
+            // Establish containing region based on aggregate padding and
+            // requested insets for the current layer.
+            container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT,
+                    bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB);
+
+            // Apply resolved gravity to drawable based on resolved size.
+            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight);
+            final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth;
+            final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight;
+            Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
+            d.setBounds(outRect);
 
             if (nest) {
                 padL += mPaddingL[i];
@@ -825,6 +1076,38 @@
         }
     }
 
+    /**
+     * Resolves layer gravity given explicit gravity and dimensions.
+     * <p>
+     * If the client hasn't specified a gravity but has specified an explicit
+     * dimension, defaults to START or TOP. Otherwise, defaults to FILL to
+     * preserve legacy behavior.
+     *
+     * @param gravity
+     * @param width
+     * @param height
+     * @return
+     */
+    private int resolveGravity(int gravity, int width, int height) {
+        if (!Gravity.isHorizontal(gravity)) {
+            if (width < 0) {
+                gravity |= Gravity.FILL_HORIZONTAL;
+            } else {
+                gravity |= Gravity.START;
+            }
+        }
+
+        if (!Gravity.isVertical(gravity)) {
+            if (height < 0) {
+                gravity |= Gravity.FILL_VERTICAL;
+            } else {
+                gravity |= Gravity.TOP;
+            }
+        }
+
+        return gravity;
+    }
+
     @Override
     public int getIntrinsicWidth() {
         int width = -1;
@@ -836,7 +1119,8 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR;
+            final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth;
+            final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR;
             if (w > width) {
                 width = w;
             }
@@ -861,7 +1145,8 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB;
+            final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight;
+            final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB;
             if (h > height) {
                 height = h;
             }
@@ -948,18 +1233,24 @@
     /** @hide */
     @Override
     public void setLayoutDirection(int layoutDirection) {
+        super.setLayoutDirection(layoutDirection);
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             array[i].mDrawable.setLayoutDirection(layoutDirection);
         }
-        super.setLayoutDirection(layoutDirection);
+        updateLayerBounds(getBounds());
     }
 
     static class ChildDrawable {
         public Drawable mDrawable;
         public int[] mThemeAttrs;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
+        public int mInsetS = UNDEFINED_INSET;
+        public int mInsetE = UNDEFINED_INSET;
+        public int mWidth = -1;
+        public int mHeight = -1;
+        public int mGravity = Gravity.NO_GRAVITY;
         public int mId = View.NO_ID;
 
         ChildDrawable() {
@@ -981,6 +1272,11 @@
             mInsetT = orig.mInsetT;
             mInsetR = orig.mInsetR;
             mInsetB = orig.mInsetB;
+            mInsetS = orig.mInsetS;
+            mInsetE = orig.mInsetE;
+            mWidth = orig.mWidth;
+            mHeight = orig.mHeight;
+            mGravity = orig.mGravity;
             mId = orig.mId;
         }
     }
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 6ec42c2..0a210d6 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -179,7 +179,7 @@
 void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
         const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
         float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
-    shadowVertexBuffer.setMode(VertexBuffer::kIndices);
+    shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
 
     // In order to computer the outer vertices in one loop, we need pre-compute
     // the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5079852..e05dd55 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -7,8 +7,13 @@
 LOCAL_SRC_FILES := \
     font/CacheTexture.cpp \
     font/Font.cpp \
+    renderstate/Blend.cpp \
+    renderstate/MeshState.cpp \
+    renderstate/PixelBufferState.cpp \
     renderstate/RenderState.cpp \
     renderstate/Scissor.cpp \
+    renderstate/Stencil.cpp \
+    renderstate/TextureState.cpp \
     renderthread/CanvasContext.cpp \
     renderthread/DrawFrameTask.cpp \
     renderthread/EglManager.cpp \
@@ -29,9 +34,9 @@
     CanvasState.cpp \
     ClipArea.cpp \
     DamageAccumulator.cpp \
-    DisplayList.cpp \
     DeferredDisplayList.cpp \
     DeferredLayerUpdater.cpp \
+    DisplayList.cpp \
     DisplayListRenderer.cpp \
     Dither.cpp \
     DrawProfiler.cpp \
@@ -39,6 +44,7 @@
     FboCache.cpp \
     FontRenderer.cpp \
     GammaFontRenderer.cpp \
+    GlopBuilder.cpp \
     GradientCache.cpp \
     Image.cpp \
     Interpolator.cpp \
@@ -60,14 +66,14 @@
     ResourceCache.cpp \
     ShadowTessellator.cpp \
     SkiaCanvas.cpp \
+    SkiaCanvasProxy.cpp \
     SkiaShader.cpp \
     Snapshot.cpp \
     SpotShadow.cpp \
-    Stencil.cpp \
     TessellationCache.cpp \
+    TextDropShadowCache.cpp \
     Texture.cpp \
-    TextureCache.cpp \
-    TextDropShadowCache.cpp
+    TextureCache.cpp
 
 intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 20dd21c..f4fc068 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -29,12 +29,10 @@
 #include <utils/String8.h>
 
 namespace android {
-
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
-
 namespace uirenderer {
 
+Caches* Caches::sInstance = nullptr;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Macros
 ///////////////////////////////////////////////////////////////////////////////
@@ -49,8 +47,14 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Caches::Caches(): Singleton<Caches>(),
-        mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(nullptr) {
+Caches::Caches(RenderState& renderState)
+        : gradientCache(mExtensions)
+        , patchCache(renderState)
+        , programCache(mExtensions)
+        , dither(*this)
+        , mRenderState(&renderState)
+        , mInitialized(false) {
+    INIT_LOGD("Creating OpenGL renderer caches");
     init();
     initFont();
     initConstraints();
@@ -60,7 +64,8 @@
     initTempProperties();
 
     mDebugLevel = readDebugLevel();
-    ALOGD("Enabling debug mode %d", mDebugLevel);
+    ALOGD_IF(mDebugLevel != kDebugDisabled,
+            "Enabling debug mode %d", mDebugLevel);
 }
 
 bool Caches::init() {
@@ -68,29 +73,8 @@
 
     ATRACE_NAME("Caches::init");
 
-    glGenBuffers(1, &meshBuffer);
-    glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
-    mCurrentBuffer = meshBuffer;
-    mCurrentIndicesBuffer = 0;
-    mCurrentPositionPointer = this;
-    mCurrentPositionStride = 0;
-    mCurrentTexCoordsPointer = this;
-    mCurrentPixelBuffer = 0;
-
-    mTexCoordsArrayEnabled = false;
-
-    glActiveTexture(gTextureUnits[0]);
-    mTextureUnit = 0;
-
     mRegionMesh = nullptr;
-    mMeshIndices = 0;
-    mShadowStripsIndices = 0;
-    blend = false;
-    lastSrcMode = GL_ZERO;
-    lastDstMode = GL_ZERO;
-    currentProgram = nullptr;
+    mProgram = nullptr;
 
     mFunctorsCount = 0;
 
@@ -98,11 +82,12 @@
     debugOverdraw = false;
     debugStencilClip = kStencilHide;
 
-    patchCache.init(*this);
+    patchCache.init();
 
     mInitialized = true;
 
-    resetBoundTextures();
+    mPixelBufferState = new PixelBufferState();
+    mTextureState = new TextureState();
 
     return true;
 }
@@ -133,12 +118,6 @@
 }
 
 void Caches::initConstraints() {
-    GLint maxTextureUnits;
-    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
-    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
-        ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
-    }
-
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 }
 
@@ -209,36 +188,47 @@
         INIT_LOGD("  Draw reorder enabled");
     }
 
-    return (prevDebugLayersUpdates != debugLayersUpdates) ||
-            (prevDebugOverdraw != debugOverdraw) ||
-            (prevDebugStencilClip != debugStencilClip);
+    return (prevDebugLayersUpdates != debugLayersUpdates)
+            || (prevDebugOverdraw != debugOverdraw)
+            || (prevDebugStencilClip != debugStencilClip);
 }
 
 void Caches::terminate() {
     if (!mInitialized) return;
-
-    glDeleteBuffers(1, &meshBuffer);
-    mCurrentBuffer = 0;
-
-    glDeleteBuffers(1, &mMeshIndices);
-    mMeshIndices = 0;
     mRegionMesh.release();
 
-    glDeleteBuffers(1, &mShadowStripsIndices);
-    mShadowStripsIndices = 0;
-
     fboCache.clear();
 
     programCache.clear();
-    currentProgram = nullptr;
+    mProgram = nullptr;
 
     patchCache.clear();
 
     clearGarbage();
 
+    delete mPixelBufferState;
+    mPixelBufferState = nullptr;
+    delete mTextureState;
+    mTextureState = nullptr;
     mInitialized = false;
 }
 
+void Caches::setProgram(const ProgramDescription& description) {
+    setProgram(programCache.get(description));
+}
+
+void Caches::setProgram(Program* program) {
+    if (!program || !program->isInUse()) {
+        if (mProgram) {
+            mProgram->remove();
+        }
+        if (program) {
+            program->use();
+        }
+        mProgram = program;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Debug
 ///////////////////////////////////////////////////////////////////////////////
@@ -268,7 +258,7 @@
             layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
     if (mRenderState) {
         int memused = 0;
-        for (std::set<const Layer*>::iterator it = mRenderState->mActiveLayers.begin();
+        for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
                 it != mRenderState->mActiveLayers.end(); it++) {
             const Layer* layer = *it;
             log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
@@ -366,216 +356,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// VBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindMeshBuffer() {
-    return bindMeshBuffer(meshBuffer);
-}
-
-bool Caches::bindMeshBuffer(const GLuint buffer) {
-    if (mCurrentBuffer != buffer) {
-        glBindBuffer(GL_ARRAY_BUFFER, buffer);
-        mCurrentBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::unbindMeshBuffer() {
-    if (mCurrentBuffer) {
-        glBindBuffer(GL_ARRAY_BUFFER, 0);
-        mCurrentBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
-    if (mCurrentIndicesBuffer != buffer) {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
-        mCurrentIndicesBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::bindQuadIndicesBuffer() {
-    if (!mMeshIndices) {
-        std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[gMaxNumberOfQuads * 6]);
-        for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
-            uint16_t quad = i * 4;
-            int index = i * 6;
-            regionIndices[index    ] = quad;       // top-left
-            regionIndices[index + 1] = quad + 1;   // top-right
-            regionIndices[index + 2] = quad + 2;   // bottom-left
-            regionIndices[index + 3] = quad + 2;   // bottom-left
-            regionIndices[index + 4] = quad + 1;   // top-right
-            regionIndices[index + 5] = quad + 3;   // bottom-right
-        }
-
-        glGenBuffers(1, &mMeshIndices);
-        bool force = bindIndicesBufferInternal(mMeshIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
-                regionIndices.get(), GL_STATIC_DRAW);
-        return force;
-    }
-
-    return bindIndicesBufferInternal(mMeshIndices);
-}
-
-bool Caches::bindShadowIndicesBuffer() {
-    if (!mShadowStripsIndices) {
-        std::unique_ptr<uint16_t[]> shadowIndices(new uint16_t[MAX_SHADOW_INDEX_COUNT]);
-        ShadowTessellator::generateShadowIndices(shadowIndices.get());
-        glGenBuffers(1, &mShadowStripsIndices);
-        bool force = bindIndicesBufferInternal(mShadowStripsIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
-            shadowIndices.get(), GL_STATIC_DRAW);
-        return force;
-    }
-
-    return bindIndicesBufferInternal(mShadowStripsIndices);
-}
-
-bool Caches::unbindIndicesBuffer() {
-    if (mCurrentIndicesBuffer) {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-        mCurrentIndicesBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindPixelBuffer(const GLuint buffer) {
-    if (mCurrentPixelBuffer != buffer) {
-        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
-        mCurrentPixelBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::unbindPixelBuffer() {
-    if (mCurrentPixelBuffer) {
-        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-        mCurrentPixelBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Meshes and textures
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
-        GLuint slot = currentProgram->position;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
-        mCurrentPositionPointer = vertices;
-        mCurrentPositionStride = stride;
-    }
-}
-
-void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
-        GLuint slot = currentProgram->texCoords;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
-        mCurrentTexCoordsPointer = vertices;
-        mCurrentTexCoordsStride = stride;
-    }
-}
-
-void Caches::resetVertexPointers() {
-    mCurrentPositionPointer = this;
-    mCurrentTexCoordsPointer = this;
-}
-
-void Caches::resetTexCoordsVertexPointer() {
-    mCurrentTexCoordsPointer = this;
-}
-
-void Caches::enableTexCoordsVertexArray() {
-    if (!mTexCoordsArrayEnabled) {
-        glEnableVertexAttribArray(Program::kBindingTexCoords);
-        mCurrentTexCoordsPointer = this;
-        mTexCoordsArrayEnabled = true;
-    }
-}
-
-void Caches::disableTexCoordsVertexArray() {
-    if (mTexCoordsArrayEnabled) {
-        glDisableVertexAttribArray(Program::kBindingTexCoords);
-        mTexCoordsArrayEnabled = false;
-    }
-}
-
-void Caches::activeTexture(GLuint textureUnit) {
-    if (mTextureUnit != textureUnit) {
-        glActiveTexture(gTextureUnits[textureUnit]);
-        mTextureUnit = textureUnit;
-    }
-}
-
-void Caches::resetActiveTexture() {
-    mTextureUnit = -1;
-}
-
-void Caches::bindTexture(GLuint texture) {
-    if (mBoundTextures[mTextureUnit] != texture) {
-        glBindTexture(GL_TEXTURE_2D, texture);
-        mBoundTextures[mTextureUnit] = texture;
-    }
-}
-
-void Caches::bindTexture(GLenum target, GLuint texture) {
-    if (target == GL_TEXTURE_2D) {
-        bindTexture(texture);
-    } else {
-        // GLConsumer directly calls glBindTexture() with
-        // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
-        // since the cached state could be stale
-        glBindTexture(target, texture);
-    }
-}
-
-void Caches::deleteTexture(GLuint texture) {
-    // When glDeleteTextures() is called on a currently bound texture,
-    // OpenGL ES specifies that the texture is then considered unbound
-    // Consider the following series of calls:
-    //
-    // glGenTextures -> creates texture name 2
-    // glBindTexture(2)
-    // glDeleteTextures(2) -> 2 is now unbound
-    // glGenTextures -> can return 2 again
-    //
-    // If we don't call glBindTexture(2) after the second glGenTextures
-    // call, any texture operation will be performed on the default
-    // texture (name=0)
-
-    unbindTexture(texture);
-
-    glDeleteTextures(1, &texture);
-}
-
-void Caches::resetBoundTextures() {
-    memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
-}
-
-void Caches::unbindTexture(GLuint texture) {
-    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
-        if (mBoundTextures[i] == texture) {
-            mBoundTextures[i] = 0;
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Tiling
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -614,7 +394,7 @@
 TextureVertex* Caches::getRegionMesh() {
     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
     if (!mRegionMesh) {
-        mRegionMesh.reset(new TextureVertex[gMaxNumberOfQuads * 4]);
+        mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
     }
 
     return mRegionMesh.get();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index fb75dd32..18bb5e6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -21,7 +21,28 @@
     #define LOG_TAG "OpenGLRenderer"
 #endif
 
+
+#include "AssetAtlas.h"
+#include "Dither.h"
+#include "Extensions.h"
+#include "FboCache.h"
+#include "GradientCache.h"
+#include "LayerCache.h"
+#include "PatchCache.h"
+#include "ProgramCache.h"
+#include "PathCache.h"
+#include "RenderBufferCache.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/TextureState.h"
+#include "ResourceCache.h"
+#include "TessellationCache.h"
+#include "TextDropShadowCache.h"
+#include "TextureCache.h"
+#include "thread/TaskProcessor.h"
+#include "thread/TaskManager.h"
+
 #include <vector>
+#include <memory>
 
 #include <GLES3/gl3.h>
 
@@ -33,90 +54,37 @@
 
 #include <SkPath.h>
 
-#include "thread/TaskProcessor.h"
-#include "thread/TaskManager.h"
-
-#include "AssetAtlas.h"
-#include "Extensions.h"
-#include "TextureCache.h"
-#include "LayerCache.h"
-#include "RenderBufferCache.h"
-#include "GradientCache.h"
-#include "PatchCache.h"
-#include "ProgramCache.h"
-#include "PathCache.h"
-#include "TessellationCache.h"
-#include "TextDropShadowCache.h"
-#include "FboCache.h"
-#include "ResourceCache.h"
-#include "Stencil.h"
-#include "Dither.h"
-
 namespace android {
 namespace uirenderer {
 
 class GammaFontRenderer;
 
 ///////////////////////////////////////////////////////////////////////////////
-// Globals
-///////////////////////////////////////////////////////////////////////////////
-
-// GL ES 2.0 defines that at least 16 texture units must be supported
-#define REQUIRED_TEXTURE_UNITS_COUNT 3
-
-// Maximum number of quads that pre-allocated meshes can draw
-static const uint32_t gMaxNumberOfQuads = 2048;
-
-// Generates simple and textured vertices
-#define FV(x, y, u, v) { x, y, u, v }
-
-// This array is never used directly but used as a memcpy source in the
-// OpenGLRenderer constructor
-static const TextureVertex gMeshVertices[] = {
-        FV(0.0f, 0.0f, 0.0f, 0.0f),
-        FV(1.0f, 0.0f, 1.0f, 0.0f),
-        FV(0.0f, 1.0f, 0.0f, 1.0f),
-        FV(1.0f, 1.0f, 1.0f, 1.0f)
-};
-static const GLsizei gMeshStride = sizeof(TextureVertex);
-static const GLsizei gVertexStride = sizeof(Vertex);
-static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
-static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
-static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
-static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
-static const GLsizei gMeshCount = 4;
-
-// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
-static const GLenum gTextureUnits[] = {
-    GL_TEXTURE0,
-    GL_TEXTURE1,
-    GL_TEXTURE2
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Debug
-///////////////////////////////////////////////////////////////////////////////
-
-struct CacheLogger {
-    CacheLogger() {
-        INIT_LOGD("Creating OpenGL renderer caches");
-    }
-}; // struct CacheLogger
-
-///////////////////////////////////////////////////////////////////////////////
 // Caches
 ///////////////////////////////////////////////////////////////////////////////
 
 class RenderNode;
 class RenderState;
 
-class ANDROID_API Caches: public Singleton<Caches> {
-    Caches();
+class ANDROID_API Caches {
+public:
+    static Caches& createInstance(RenderState& renderState) {
+        LOG_ALWAYS_FATAL_IF(sInstance, "double create of Caches attempted");
+        sInstance = new Caches(renderState);
+        return *sInstance;
+    }
 
-    friend class Singleton<Caches>;
+    static Caches& getInstance() {
+        LOG_ALWAYS_FATAL_IF(!sInstance, "instance not yet created");
+        return *sInstance;
+    }
 
-    CacheLogger mLogger;
+    static bool hasInstance() {
+        return sInstance != 0;
+    }
+private:
+    Caches(RenderState& renderState);
+    static Caches* sInstance;
 
 public:
     enum FlushMode {
@@ -135,8 +103,6 @@
      */
     bool initProperties();
 
-    void setRenderState(RenderState* renderState) { mRenderState = renderState; }
-
     /**
      * Flush the cache.
      *
@@ -175,102 +141,6 @@
      */
     void deleteLayerDeferred(Layer* layer);
 
-    /**
-     * Binds the VBO used to render simple textured quads.
-     */
-    bool bindMeshBuffer();
-
-    /**
-     * Binds the specified VBO if needed.
-     */
-    bool bindMeshBuffer(const GLuint buffer);
-
-    /**
-     * Unbinds the VBO used to render simple textured quads.
-     */
-    bool unbindMeshBuffer();
-
-    /**
-     * Binds a global indices buffer that can draw up to
-     * gMaxNumberOfQuads quads.
-     */
-    bool bindQuadIndicesBuffer();
-    bool bindShadowIndicesBuffer();
-    bool unbindIndicesBuffer();
-
-    /**
-     * Binds the specified buffer as the current GL unpack pixel buffer.
-     */
-    bool bindPixelBuffer(const GLuint buffer);
-
-    /**
-     * Resets the current unpack pixel buffer to 0 (default value.)
-     */
-    bool unbindPixelBuffer();
-
-    /**
-     * Binds an attrib to the specified float vertex pointer.
-     * Assumes a stride of gMeshStride and a size of 2.
-     */
-    void bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
-    /**
-     * Binds an attrib to the specified float vertex pointer.
-     * Assumes a stride of gMeshStride and a size of 2.
-     */
-    void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
-    /**
-     * Resets the vertex pointers.
-     */
-    void resetVertexPointers();
-    void resetTexCoordsVertexPointer();
-
-    void enableTexCoordsVertexArray();
-    void disableTexCoordsVertexArray();
-
-    /**
-     * Activate the specified texture unit. The texture unit must
-     * be specified using an integer number (0 for GL_TEXTURE0 etc.)
-     */
-    void activeTexture(GLuint textureUnit);
-
-    /**
-     * Invalidate the cached value of the active texture unit.
-     */
-    void resetActiveTexture();
-
-    /**
-     * Binds the specified texture as a GL_TEXTURE_2D texture.
-     * All texture bindings must be performed with this method or
-     * bindTexture(GLenum, GLuint).
-     */
-    void bindTexture(GLuint texture);
-
-    /**
-     * Binds the specified texture with the specified render target.
-     * All texture bindings must be performed with this method or
-     * bindTexture(GLuint).
-     */
-    void bindTexture(GLenum target, GLuint texture);
-
-    /**
-     * Deletes the specified texture and clears it from the cache
-     * of bound textures.
-     * All textures must be deleted using this method.
-     */
-    void deleteTexture(GLuint texture);
-
-    /**
-     * Signals that the cache of bound textures should be cleared.
-     * Other users of the context may have altered which textures are bound.
-     */
-    void resetBoundTextures();
-
-    /**
-     * Clear the cache of bound textures.
-     */
-    void unbindTexture(GLuint texture);
 
     void startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard);
     void endTiling();
@@ -292,17 +162,9 @@
     void registerFunctors(uint32_t functorCount);
     void unregisterFunctors(uint32_t functorCount);
 
-    bool blend;
-    GLenum lastSrcMode;
-    GLenum lastDstMode;
-    Program* currentProgram;
-
     bool drawDeferDisabled;
     bool drawReorderDisabled;
 
-    // VBO to draw with
-    GLuint meshBuffer;
-
     // Misc
     GLint maxTextureSize;
 
@@ -316,14 +178,18 @@
         kStencilShowRegion
     };
     StencilClipDebug debugStencilClip;
-
+private:
+    // Declared before gradientCache and programCache which need this to initialize.
+    // TODO: cleanup / move elsewhere
+    Extensions mExtensions;
+public:
     TextureCache textureCache;
     LayerCache layerCache;
     RenderBufferCache renderBufferCache;
     GradientCache gradientCache;
-    ProgramCache programCache;
-    PathCache pathCache;
     PatchCache patchCache;
+    PathCache pathCache;
+    ProgramCache programCache;
     TessellationCache tessellationCache;
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
@@ -333,7 +199,6 @@
     TaskManager tasks;
 
     Dither dither;
-    Stencil stencil;
 
     bool gpuPixelBuffersEnabled;
 
@@ -356,6 +221,14 @@
     int propertyAmbientShadowStrength;
     int propertySpotShadowStrength;
 
+    void setProgram(const ProgramDescription& description);
+    void setProgram(Program* program);
+
+    Extensions& extensions() { return mExtensions; }
+    Program& program() { return *mProgram; }
+    PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
+    TextureState& textureState() { return *mTextureState; }
+
 private:
     enum OverdrawColorSet {
         kColorSet_Default = 0,
@@ -367,8 +240,6 @@
     void initConstraints();
     void initStaticProperties();
 
-    bool bindIndicesBufferInternal(const GLuint buffer);
-
     static void eventMarkNull(GLsizei length, const GLchar* marker) { }
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
     static void endMarkNull() { }
@@ -381,27 +252,11 @@
         if (label) *label = '\0';
     }
 
-    GLuint mCurrentBuffer;
-    GLuint mCurrentIndicesBuffer;
-    GLuint mCurrentPixelBuffer;
-    const void* mCurrentPositionPointer;
-    GLsizei mCurrentPositionStride;
-    const void* mCurrentTexCoordsPointer;
-    GLsizei mCurrentTexCoordsStride;
-
-    bool mTexCoordsArrayEnabled;
-
-    GLuint mTextureUnit;
-
-    Extensions& mExtensions;
+    RenderState* mRenderState;
 
     // Used to render layers
     std::unique_ptr<TextureVertex[]> mRegionMesh;
 
-    // Global index buffer
-    GLuint mMeshIndices;
-    GLuint mShadowStripsIndices;
-
     mutable Mutex mGarbageLock;
     Vector<Layer*> mLayerGarbage;
 
@@ -410,12 +265,13 @@
 
     uint32_t mFunctorsCount;
 
-    // Caches texture bindings for the GL_TEXTURE_2D target
-    GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
-
     OverdrawColorSet mOverdrawDebugColorSet;
 
-    RenderState* mRenderState;
+    // TODO: move below to RenderState
+    PixelBufferState* mPixelBufferState = nullptr;
+    TextureState* mTextureState = nullptr;
+    Program* mProgram = nullptr; // note: object owned by ProgramCache
+
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index f9c8620..7ad0683 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -42,15 +42,15 @@
      */
     static Canvas* create_canvas(SkCanvas* skiaCanvas);
 
-    // TODO: enable HWUI to either create similar canvas wrapper or subclass
-    //       directly from Canvas
-    //static Canvas* create_canvas(uirenderer::Renderer* renderer);
-
-    // TODO: this is a temporary affordance until all necessary logic can be
-    //       moved within this interface! Further, the return value should
-    //       NOT be unref'd and is valid until this canvas is destroyed or a
-    //       new bitmap is set.
-    virtual SkCanvas* getSkCanvas() = 0;
+    /**
+     *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
+     *  It is useful for testing and clients (e.g. Picture/Movie) that expect to
+     *  draw their contents into an SkCanvas.
+     *
+     *  Further, the returned SkCanvas should NOT be unref'd and is valid until
+     *  this canvas is destroyed or a new bitmap is set.
+     */
+    virtual SkCanvas* asSkCanvas() = 0;
 
     virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index d128ffe..cca8a06 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -668,7 +668,8 @@
     }
 
     virtual void output(int level, uint32_t logFlags) const override {
-        OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top,
+        OP_LOG("Draw bitmap %p of size %dx%d%s",
+                mBitmap, mBitmap->width(), mBitmap->height(),
                 mEntry ? " using AssetAtlas" : "");
     }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index d98d744..23181bc 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -59,6 +59,7 @@
     mPathMap.clear();
     DisplayListData* data = mDisplayListData;
     mDisplayListData = nullptr;
+    mSkiaCanvasProxy.reset(nullptr);
     return data;
 }
 
@@ -94,6 +95,15 @@
     mDisplayListData->functors.add(functor);
 }
 
+SkCanvas* DisplayListRenderer::asSkCanvas() {
+    LOG_ALWAYS_FATAL_IF(!mDisplayListData,
+            "attempting to get an SkCanvas when we are not recording!");
+    if (!mSkiaCanvasProxy) {
+        mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
+    }
+    return mSkiaCanvasProxy.get();
+}
+
 int DisplayListRenderer::save(SkCanvas::SaveFlags flags) {
     addStateOp(new (alloc()) SaveOp((int) flags));
     return mState.save((int) flags);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index d2b3ead..bd0b3b7 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -28,6 +28,7 @@
 #include "Canvas.h"
 #include "CanvasState.h"
 #include "DisplayList.h"
+#include "SkiaCanvasProxy.h"
 #include "RenderNode.h"
 #include "Renderer.h"
 #include "ResourceCache.h"
@@ -136,10 +137,8 @@
 // ----------------------------------------------------------------------------
 // android/graphics/Canvas interface
 // ----------------------------------------------------------------------------
-    virtual SkCanvas* getSkCanvas() override {
-        LOG_ALWAYS_FATAL("DisplayListRenderer has no SkCanvas");
-        return nullptr;
-    }
+    virtual SkCanvas* asSkCanvas() override;
+
     virtual void setBitmap(SkBitmap* bitmap, bool copyState) override {
         LOG_ALWAYS_FATAL("DisplayListRenderer is not backed by a bitmap.");
     }
@@ -244,6 +243,7 @@
 private:
 
     CanvasState mState;
+    std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy;
 
     enum DeferredBarrierType {
         kBarrier_None,
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 12d9389..1ba6511 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -24,15 +24,16 @@
 // Lifecycle
 ///////////////////////////////////////////////////////////////////////////////
 
-Dither::Dither(): mCaches(nullptr), mInitialized(false), mDitherTexture(0) {
+Dither::Dither(Caches& caches)
+        : mCaches(caches)
+        , mInitialized(false)
+        , mDitherTexture(0) {
 }
 
 void Dither::bindDitherTexture() {
     if (!mInitialized) {
-        bool useFloatTexture = Extensions::getInstance().hasFloatTextures();
-
         glGenTextures(1, &mDitherTexture);
-        mCaches->bindTexture(mDitherTexture);
+        mCaches.textureState().bindTexture(mDitherTexture);
 
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -40,7 +41,7 @@
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
-        if (useFloatTexture) {
+        if (mCaches.extensions().hasFloatTextures()) {
             // We use a R16F texture, let's remap the alpha channel to the
             // red channel to avoid changing the shader sampling code on GL ES 3.0+
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
@@ -71,13 +72,13 @@
 
         mInitialized = true;
     } else {
-        mCaches->bindTexture(mDitherTexture);
+        mCaches.textureState().bindTexture(mDitherTexture);
     }
 }
 
 void Dither::clear() {
     if (mInitialized) {
-        mCaches->deleteTexture(mDitherTexture);
+        mCaches.textureState().deleteTexture(mDitherTexture);
         mInitialized = false;
     }
 }
@@ -86,15 +87,13 @@
 // Program management
 ///////////////////////////////////////////////////////////////////////////////
 
-void Dither::setupProgram(Program* program, GLuint* textureUnit) {
-    if (!mCaches) mCaches = &Caches::getInstance();
-
+void Dither::setupProgram(Program& program, GLuint* textureUnit) {
     GLuint textureSlot = (*textureUnit)++;
-    mCaches->activeTexture(textureSlot);
+    mCaches.textureState().activateTexture(textureSlot);
 
     bindDitherTexture();
 
-    glUniform1i(program->getUniform("ditherSampler"), textureSlot);
+    glUniform1i(program.getUniform("ditherSampler"), textureSlot);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
index 092ebf2..b589b80 100644
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -23,6 +23,7 @@
 namespace uirenderer {
 
 class Caches;
+class Extensions;
 class Program;
 
 // Must be a power of two
@@ -36,15 +37,15 @@
  */
 class Dither {
 public:
-    Dither();
+    Dither(Caches& caches);
 
     void clear();
-    void setupProgram(Program* program, GLuint* textureUnit);
+    void setupProgram(Program& program, GLuint* textureUnit);
 
 private:
     void bindDitherTexture();
 
-    Caches* mCaches;
+    Caches& mCaches;
     bool mInitialized;
     GLuint mDitherTexture;
 };
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 8352c3f..c68822b 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -16,18 +16,16 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
+#include "Extensions.h"
+
+#include "Debug.h"
+#include "Properties.h"
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-
+#include <GLES2/gl2ext.h>
 #include <utils/Log.h>
 
-#include "Debug.h"
-#include "Extensions.h"
-#include "Properties.h"
-
 namespace android {
 
 using namespace uirenderer;
@@ -50,7 +48,7 @@
 // Constructors
 ///////////////////////////////////////////////////////////////////////////////
 
-Extensions::Extensions(): Singleton<Extensions>() {
+Extensions::Extensions() {
     // Query GL extensions
     findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList);
     mHasNPot = hasGlExtension("GL_OES_texture_npot");
@@ -93,9 +91,6 @@
     }
 }
 
-Extensions::~Extensions() {
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Methods
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 25d4c5e..731001a 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -23,6 +23,8 @@
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 
+#include <GLES2/gl2.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -30,8 +32,10 @@
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
-class ANDROID_API Extensions: public Singleton<Extensions> {
+class ANDROID_API Extensions {
 public:
+    Extensions();
+
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
@@ -55,13 +59,8 @@
     void dump() const;
 
 private:
-    Extensions();
-    ~Extensions();
-
     void findExtensions(const char* extensions, SortedVector<String8>& list) const;
 
-    friend class Singleton<Extensions>;
-
     SortedVector<String8> mGlExtensionList;
     SortedVector<String8> mEglExtensionList;
 
diff --git a/libs/hwui/Fence.h b/libs/hwui/Fence.h
deleted file mode 100644
index fc29f7ac1..0000000
--- a/libs/hwui/Fence.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_FENCE_H
-#define ANDROID_HWUI_FENCE_H
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Creating a Fence instance inserts a new sync fence in the OpenGL
- * commands stream. The caller can then wait for the fence to be signaled
- * by calling the wait method.
- */
-class Fence {
-public:
-    enum {
-        /**
-         * Default timeout in nano-seconds for wait()
-         */
-        kDefaultTimeout = 1000000000
-    };
-
-    /**
-     * Inserts a new sync fence in the OpenGL commands stream.
-     */
-    Fence() {
-        mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        if (mDisplay != EGL_NO_DISPLAY) {
-            mFence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, nullptr);
-        } else {
-            mFence = EGL_NO_SYNC_KHR;
-        }
-    }
-
-    /**
-     * Destroys the fence. Any caller waiting on the fence will be
-     * signaled immediately.
-     */
-    ~Fence() {
-        if (mFence != EGL_NO_SYNC_KHR) {
-            eglDestroySyncKHR(mDisplay, mFence);
-        }
-    }
-
-    /**
-     * Blocks the calling thread until this fence is signaled, or until
-     * <timeout> nanoseconds have passed.
-     *
-     * Returns true if waiting for the fence was successful, false if
-     * a timeout or an error occurred.
-     */
-    bool wait(EGLTimeKHR timeout = kDefaultTimeout) {
-        EGLint waitStatus = eglClientWaitSyncKHR(mDisplay, mFence,
-                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, timeout);
-        if (waitStatus == EGL_FALSE) {
-            ALOGW("Failed to wait for the fence %#x", eglGetError());
-        }
-        return waitStatus == EGL_CONDITION_SATISFIED_KHR;
-    }
-
-private:
-    EGLDisplay mDisplay;
-    EGLSyncKHR mFence;
-
-}; // class Fence
-
-/**
- * An AutoFence creates a Fence instance and waits for the fence
- * to be signaled when the AutoFence is destroyed. This is useful
- * to automatically wait for a series of OpenGL commands to be
- * executed. For example:
- *
- * void drawAndWait() {
- *     glDrawElements();
- *     AutoFence fence;
- * }
- */
-class AutoFence {
-public:
-    AutoFence(EGLTimeKHR timeout = Fence::kDefaultTimeout): mTimeout(timeout) {
-    }
-
-    ~AutoFence() {
-        mFence.wait(mTimeout);
-    }
-
-private:
-    EGLTimeKHR mTimeout;
-    Fence mFence;
-
-}; // class AutoFence
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_FENCE_H
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
new file mode 100644
index 0000000..803b9d4
--- /dev/null
+++ b/libs/hwui/FloatColor.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef FLOATCOLOR_H
+#define FLOATCOLOR_H
+
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+struct FloatColor {
+    float r;
+    float g;
+    float b;
+    float a;
+};
+
+REQUIRE_COMPATIBLE_LAYOUT(FloatColor);
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* FLOATCOLOR_H */
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index a0bc7b0..55b2d19 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -14,7 +14,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
+#include "FontRenderer.h"
+
+#include "Caches.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "OpenGLRenderer.h"
+#include "PixelBuffer.h"
+#include "Rect.h"
+#include "renderstate/RenderState.h"
+#include "utils/Blur.h"
+#include "utils/Timing.h"
 
 #include <SkGlyph.h>
 #include <SkUtils.h>
@@ -27,17 +37,6 @@
 #include <RenderScript.h>
 #endif
 
-#include "utils/Blur.h"
-#include "utils/Timing.h"
-
-#include "Caches.h"
-#include "Debug.h"
-#include "Extensions.h"
-#include "FontRenderer.h"
-#include "OpenGLRenderer.h"
-#include "PixelBuffer.h"
-#include "Rect.h"
-
 namespace android {
 namespace uirenderer {
 
@@ -47,9 +46,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // TextSetupFunctor
 ///////////////////////////////////////////////////////////////////////////////
-status_t TextSetupFunctor::operator ()(int what, void* data) {
-    Data* typedData = reinterpret_cast<Data*>(data);
-    GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
+status_t TextSetupFunctor::setup(GLenum glyphFormat) {
 
     renderer->setupDraw();
     renderer->setupDrawTextGamma(paint);
@@ -287,7 +284,7 @@
     uint32_t cacheWidth = cacheTexture->getWidth();
 
     if (!cacheTexture->getPixelBuffer()) {
-        Caches::getInstance().activeTexture(0);
+        Caches::getInstance().textureState().activateTexture(0);
         // Large-glyph texture memory is allocated only as needed
         cacheTexture->allocateTexture();
     }
@@ -397,10 +394,10 @@
 
 CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
         bool allocate) {
-    CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
+    CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
 
     if (allocate) {
-        Caches::getInstance().activeTexture(0);
+        Caches::getInstance().textureState().activateTexture(0);
         cacheTexture->allocateTexture();
         cacheTexture->allocateMesh();
     }
@@ -446,8 +443,8 @@
         if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
             if (cacheTexture->getTextureId() != lastTextureId) {
                 lastTextureId = cacheTexture->getTextureId();
-                caches.activeTexture(0);
-                caches.bindTexture(lastTextureId);
+                caches.textureState().activateTexture(0);
+                caches.textureState().bindTexture(lastTextureId);
             }
 
             if (cacheTexture->upload()) {
@@ -473,7 +470,7 @@
     checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
 
     // Unbind any PBO we might have used to update textures
-    caches.unbindPixelBuffer();
+    caches.pixelBufferState().unbind();
 
     // Reset to default unpack row length to avoid affecting texture
     // uploads in other parts of the renderer
@@ -485,44 +482,48 @@
 }
 
 void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
-    Caches& caches = Caches::getInstance();
+    if (!mFunctor) return;
+
+    Caches& caches = mFunctor->renderer->getCaches();
+    RenderState& renderState = mFunctor->renderer->renderState();
+
     bool first = true;
-    bool force = false;
+    bool forceRebind = false;
     for (uint32_t i = 0; i < cacheTextures.size(); i++) {
         CacheTexture* texture = cacheTextures[i];
         if (texture->canDraw()) {
             if (first) {
                 if (mFunctor) {
-                    TextSetupFunctor::Data functorData(texture->getFormat());
-                    (*mFunctor)(0, &functorData);
+                    mFunctor->setup(texture->getFormat());
                 }
 
                 checkTextureUpdate();
-                caches.bindQuadIndicesBuffer();
+                renderState.meshState().bindQuadIndicesBuffer();
 
                 if (!mDrawn) {
                     // If returns true, a VBO was bound and we must
                     // rebind our vertex attrib pointers even if
                     // they have the same values as the current pointers
-                    force = caches.unbindMeshBuffer();
+                    forceRebind = renderState.meshState().unbindMeshBuffer();
                 }
 
-                caches.activeTexture(0);
+                caches.textureState().activateTexture(0);
                 first = false;
             }
 
-            caches.bindTexture(texture->getTextureId());
+            caches.textureState().bindTexture(texture->getTextureId());
             texture->setLinearFiltering(mLinearFiltering, false);
 
             TextureVertex* mesh = texture->mesh();
-            caches.bindPositionVertexPointer(force, &mesh[0].x);
-            caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
-            force = false;
+            MeshState& meshState = renderState.meshState();
+            meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
+            meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
 
             glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
                     GL_UNSIGNED_SHORT, texture->indices());
 
             texture->resetMesh();
+            forceRebind = false;
         }
     }
 }
@@ -647,7 +648,7 @@
                 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
 
         // Unbind any PBO we might have used
-        Caches::getInstance().unbindPixelBuffer();
+        Caches::getInstance().pixelBufferState().unbind();
 
         blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
     }
@@ -661,7 +662,7 @@
     return image;
 }
 
-void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
     checkInit();
 
     mDrawn = false;
@@ -689,7 +690,7 @@
 
 bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
-        const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
+        const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
@@ -707,7 +708,7 @@
 
 bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
-        float hOffset, float vOffset, Rect* bounds, Functor* functor) {
+        float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 668ee64..cb63684 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,7 +17,12 @@
 #ifndef ANDROID_HWUI_FONT_RENDERER_H
 #define ANDROID_HWUI_FONT_RENDERER_H
 
-#include <utils/Functor.h>
+#include "font/FontUtil.h"
+#include "font/CacheTexture.h"
+#include "font/CachedGlyphInfo.h"
+#include "font/Font.h"
+#include "utils/SortedList.h"
+
 #include <utils/LruCache.h>
 #include <utils/Vector.h>
 #include <utils/StrongPointer.h>
@@ -26,12 +31,6 @@
 
 #include <GLES2/gl2.h>
 
-#include "font/FontUtil.h"
-#include "font/CacheTexture.h"
-#include "font/CachedGlyphInfo.h"
-#include "font/Font.h"
-#include "utils/SortedList.h"
-
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
 #include "RenderScript.h"
 namespace RSC {
@@ -47,26 +46,20 @@
 
 class OpenGLRenderer;
 
-///////////////////////////////////////////////////////////////////////////////
-// TextSetupFunctor
-///////////////////////////////////////////////////////////////////////////////
-class TextSetupFunctor: public Functor {
+class TextSetupFunctor {
 public:
-    struct Data {
-        Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
-        }
-
-        GLenum glyphFormat;
-    };
-
     TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
-            int alpha, SkXfermode::Mode mode, const SkPaint* paint): Functor(),
-            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
-            alpha(alpha), mode(mode), paint(paint) {
+            int alpha, SkXfermode::Mode mode, const SkPaint* paint)
+        : renderer(renderer)
+        , x(x)
+        , y(y)
+        , pureTranslate(pureTranslate)
+        , alpha(alpha)
+        , mode(mode)
+        , paint(paint) {
     }
-    ~TextSetupFunctor() { }
 
-    status_t operator ()(int what, void* data) override;
+    status_t setup(GLenum glyphFormat);
 
     OpenGLRenderer* renderer;
     float x;
@@ -77,10 +70,6 @@
     const SkPaint* paint;
 };
 
-///////////////////////////////////////////////////////////////////////////////
-// FontRenderer
-///////////////////////////////////////////////////////////////////////////////
-
 class FontRenderer {
 public:
     FontRenderer();
@@ -101,22 +90,14 @@
     // bounds is an out parameter
     bool renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, const float* positions,
-            Rect* bounds, Functor* functor, bool forceFinish = true);
+            Rect* bounds, TextSetupFunctor* functor, bool forceFinish = true);
 
     // bounds is an out parameter
     bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
-            float hOffset, float vOffset, Rect* bounds, Functor* functor);
+            float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor);
 
     struct DropShadow {
-        DropShadow() { };
-
-        DropShadow(const DropShadow& dropShadow):
-            width(dropShadow.width), height(dropShadow.height),
-            image(dropShadow.image), penX(dropShadow.penX),
-            penY(dropShadow.penY) {
-        }
-
         uint32_t width;
         uint32_t height;
         uint8_t* image;
@@ -152,7 +133,7 @@
     void flushAllAndInvalidate();
 
     void checkInit();
-    void initRender(const Rect* clip, Rect* bounds, Functor* functor);
+    void initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor);
     void finishRender();
 
     void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
@@ -193,7 +174,7 @@
 
     bool mUploadTexture;
 
-    Functor* mFunctor;
+    TextSetupFunctor* mFunctor;
     const Rect* mClip;
     Rect* mBounds;
     bool mDrawn;
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index e97a477..0bcd83a 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
-
 #include "Debug.h"
 #include "GammaFontRenderer.h"
 #include "Properties.h"
@@ -96,7 +94,8 @@
 // Shader-based renderer
 ///////////////////////////////////////////////////////////////////////////////
 
-ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() {
+ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma)
+        : GammaFontRenderer() {
     INIT_LOGD("Creating shader gamma font renderer");
     mRenderer = nullptr;
     mMultiGamma = multiGamma;
@@ -123,9 +122,9 @@
 }
 
 void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description,
-        Program* program) const {
+        Program& program) const {
     if (description.hasGammaCorrection) {
-        glUniform1f(program->getUniform("gamma"), description.gamma);
+        glUniform1f(program.getUniform("gamma"), description.gamma);
     }
 }
 
@@ -139,7 +138,8 @@
 // Lookup-based renderer
 ///////////////////////////////////////////////////////////////////////////////
 
-LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() {
+LookupGammaFontRenderer::LookupGammaFontRenderer()
+        : GammaFontRenderer() {
     INIT_LOGD("Creating lookup gamma font renderer");
 
     // Compute the gamma tables
@@ -162,7 +162,8 @@
 // Lookup-based renderer, using 3 different correction tables
 ///////////////////////////////////////////////////////////////////////////////
 
-Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() {
+Lookup3GammaFontRenderer::Lookup3GammaFontRenderer()
+        : GammaFontRenderer() {
     INIT_LOGD("Creating lookup3 gamma font renderer");
 
     // Compute the gamma tables
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 19352d7..ca55bf1 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -38,7 +38,7 @@
     virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0;
 
     virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
-    virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
+    virtual void setupProgram(ProgramDescription& description, Program& program) const = 0;
 
     virtual void endPrecaching() = 0;
 
@@ -86,7 +86,7 @@
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const override;
-    void setupProgram(ProgramDescription& description, Program* program) const override;
+    void setupProgram(ProgramDescription& description, Program& program) const override;
 
     void endPrecaching() override;
 
@@ -135,7 +135,7 @@
     void describe(ProgramDescription& description, const SkPaint* paint) const override {
     }
 
-    void setupProgram(ProgramDescription& description, Program* program) const override {
+    void setupProgram(ProgramDescription& description, Program& program) const override {
     }
 
     void endPrecaching() override;
@@ -171,7 +171,7 @@
     void describe(ProgramDescription& description, const SkPaint* paint) const override {
     }
 
-    void setupProgram(ProgramDescription& description, Program* program) const override {
+    void setupProgram(ProgramDescription& description, Program& program) const override {
     }
 
     void endPrecaching() override;
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
new file mode 100644
index 0000000..12c6e45
--- /dev/null
+++ b/libs/hwui/Glop.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_GLOP_H
+#define ANDROID_HWUI_GLOP_H
+
+#include "FloatColor.h"
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/Macros.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+class RoundRectClipState;
+
+/*
+ * Enumerates optional vertex attributes
+ *
+ * Position is always enabled by MeshState, these other attributes
+ * are enabled/disabled dynamically based on mesh content.
+ */
+enum VertexAttribFlags {
+    // NOTE: position attribute always enabled
+    kNone_Attrib = 0,
+    kTextureCoord_Attrib = 1 << 0,
+    kColor_Attrib = 1 << 1,
+    kAlpha_Attrib = 1 << 2,
+};
+
+/**
+ * Structure containing all data required to issue an OpenGL draw
+ *
+ * Includes all of the mesh, fill, and GL state required to perform
+ * the operation. Pieces of data are either directly copied into the
+ * structure, or stored as a pointer or GL object reference to data
+ * managed.
+ *
+ * Eventually, a Glop should be able to be drawn multiple times from
+ * a single construction, up until GL context destruction. Currently,
+ * vertex/index/Texture/RoundRectClipState pointers prevent this from
+ * being safe.
+ */
+// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
+struct Glop {
+    Rect bounds;
+    const RoundRectClipState* roundRectClipState;
+
+    /*
+     * Stores mesh - vertex and index data.
+     *
+     * buffer objects and void*s are mutually exclusive
+     * indices are optional, currently only GL_UNSIGNED_SHORT supported
+     */
+    struct Mesh {
+        VertexAttribFlags vertexFlags;
+        GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
+        GLuint vertexBufferObject;
+        GLuint indexBufferObject;
+        const void* vertices;
+        const void* indices;
+        int elementCount;
+        GLsizei stride;
+        GLvoid* texCoordOffset;
+        TextureVertex mappedVertices[4];
+    } mesh;
+
+    struct Fill {
+        Program* program;
+        Texture* texture;
+        GLenum textureFilter;
+
+        bool colorEnabled;
+        FloatColor color;
+
+        /* TODO
+        union shader {
+            //...
+        }; TODO
+        */
+        ProgramDescription::ColorFilterMode filterMode;
+        union Filter {
+            struct Matrix {
+                float matrix[16];
+                float vector[4];
+            } matrix;
+            FloatColor color;
+        } filter;
+    } fill;
+
+    struct Transform {
+        Matrix4 ortho; // TODO: out of op, since this is static per FBO
+        Matrix4 modelView;
+        Matrix4 canvas;
+        bool fudgingOffset;
+    } transform;
+
+    struct Blend {
+        GLenum src;
+        GLenum dst;
+    } blend;
+
+    /**
+     * Additional render state to enumerate:
+     * - scissor + (bits for whether each of LTRB needed?)
+     * - stencil mode (draw into, mask, count, etc)
+     */
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // ANDROID_HWUI_GLOP_H
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
new file mode 100644
index 0000000..e56988c
--- /dev/null
+++ b/libs/hwui/GlopBuilder.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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 "GlopBuilder.h"
+
+#include "Caches.h"
+#include "Glop.h"
+#include "Matrix.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/RenderState.h"
+#include "SkiaShader.h"
+#include "Texture.h"
+#include "utils/PaintUtils.h"
+#include "VertexBuffer.h"
+
+#include <GLES2/gl2.h>
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+#define TRIGGER_STAGE(stageFlag) \
+    LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
+    mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
+
+#define REQUIRE_STAGES(requiredFlags) \
+    LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
+            "not prepared for current stage")
+
+static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {;
+    TextureVertex::setUV(quadVertex++, uvs.left, uvs.top);
+    TextureVertex::setUV(quadVertex++, uvs.right, uvs.top);
+    TextureVertex::setUV(quadVertex++, uvs.left, uvs.bottom);
+    TextureVertex::setUV(quadVertex++, uvs.right, uvs.bottom);
+}
+
+GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
+        : mRenderState(renderState)
+        , mCaches(caches)
+        , mOutGlop(outGlop) {
+    mStageFlags = kInitialStage;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Mesh
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setMeshUnitQuad() {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.vertexFlags = kNone_Attrib;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+    mOutGlop->mesh.vertices = nullptr;
+    mOutGlop->mesh.indexBufferObject = 0;
+    mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.elementCount = 4;
+    mOutGlop->mesh.stride = kTextureVertexStride;
+    mOutGlop->mesh.texCoordOffset = nullptr;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper,
+        bool isAlphaMaskTexture) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+
+    if (CC_UNLIKELY(uvMapper)) {
+        Rect uvs(0, 0, 1, 1);
+        uvMapper->map(uvs);
+        setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
+
+        mOutGlop->mesh.vertexBufferObject = 0;
+        mOutGlop->mesh.vertices = &mOutGlop->mesh.mappedVertices[0];
+    } else {
+        // standard UV coordinates, use regular unit quad VBO
+        mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+        mOutGlop->mesh.vertices = nullptr;
+    }
+    mOutGlop->mesh.indexBufferObject = 0;
+    mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.elementCount = 4;
+    mOutGlop->mesh.stride = kTextureVertexStride;
+    mOutGlop->mesh.texCoordOffset = (GLvoid*) kMeshTextureOffset;
+
+    mDescription.hasTexture = true;
+    mDescription.hasAlpha8Texture = isAlphaMaskTexture;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.vertexFlags = kNone_Attrib;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.vertexBufferObject = 0;
+    mOutGlop->mesh.vertices = vertexData;
+    mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
+    mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.elementCount = 6 * quadCount;
+    mOutGlop->mesh.stride = kVertexStride;
+    mOutGlop->mesh.texCoordOffset = nullptr;
+
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
+    TRIGGER_STAGE(kMeshStage);
+
+    const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags();
+
+    bool alphaVertex = flags & VertexBuffer::kAlpha;
+    bool indices = flags & VertexBuffer::kIndices;
+    mOutGlop->mesh.vertexFlags = alphaVertex ? kAlpha_Attrib : kNone_Attrib;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.vertexBufferObject = 0;
+    mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
+    mOutGlop->mesh.indexBufferObject = 0;
+    mOutGlop->mesh.indices = vertexBuffer.getIndices();
+    mOutGlop->mesh.elementCount = indices
+            ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+    mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
+
+    mDescription.hasVertexAlpha = alphaVertex;
+    mDescription.useShadowAlphaInterp = shadowInterp;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Fill
+////////////////////////////////////////////////////////////////////////////////
+
+void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode,
+        const SkShader* shader, const SkColorFilter* colorFilter) {
+    if (mode != SkXfermode::kClear_Mode) {
+        float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
+        if (!shader) {
+            float colorScale = alpha / 255.0f;
+            mOutGlop->fill.color = {
+                    colorScale * SkColorGetR(color),
+                    colorScale * SkColorGetG(color),
+                    colorScale * SkColorGetB(color),
+                    alpha
+            };
+        } else {
+            mOutGlop->fill.color = { 1, 1, 1, alpha };
+        }
+    } else {
+        mOutGlop->fill.color = { 0, 0, 0, 1 };
+    }
+    const bool SWAP_SRC_DST = false;
+
+    mOutGlop->blend = { GL_ZERO, GL_ZERO };
+    if (mOutGlop->fill.color.a < 1.0f
+            || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+            || (mOutGlop->fill.texture && mOutGlop->fill.texture->blend)
+            || mOutGlop->roundRectClipState
+            || PaintUtils::isBlendedShader(shader)
+            || PaintUtils::isBlendedColorFilter(colorFilter)
+            || mode != SkXfermode::kSrcOver_Mode) {
+        if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
+            Blend::getFactors(mode, SWAP_SRC_DST,
+                    &mOutGlop->blend.src, &mOutGlop->blend.dst);
+        } else {
+            // These blend modes are not supported by OpenGL directly and have
+            // to be implemented using shaders. Since the shader will perform
+            // the blending, don't enable GL blending off here
+            // If the blend mode cannot be implemented using shaders, fall
+            // back to the default SrcOver blend mode instead
+            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
+                mDescription.framebufferMode = mode;
+                mDescription.swapSrcDst = SWAP_SRC_DST;
+                // blending in shader, don't enable
+            } else {
+                // unsupported
+                Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+                        &mOutGlop->blend.src, &mOutGlop->blend.dst);
+            }
+        }
+    }
+
+    if (shader) {
+        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
+        // TODO: store shader data
+        LOG_ALWAYS_FATAL("shaders not yet supported");
+    }
+
+    if (colorFilter) {
+        SkColor color;
+        SkXfermode::Mode mode;
+        SkScalar srcColorMatrix[20];
+        if (colorFilter->asColorMode(&color, &mode)) {
+            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
+            mDescription.colorMode = mode;
+
+            const float alpha = SkColorGetA(color) / 255.0f;
+            float colorScale = alpha / 255.0f;
+            mOutGlop->fill.filter.color = {
+                    colorScale * SkColorGetR(color),
+                    colorScale * SkColorGetG(color),
+                    colorScale * SkColorGetB(color),
+                    alpha,
+            };
+        } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
+            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
+
+            float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
+            memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
+            memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
+            memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
+            memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
+
+            // Skia uses the range [0..255] for the addition vector, but we need
+            // the [0..1] range to apply the vector in GLSL
+            float* colorVector = mOutGlop->fill.filter.matrix.vector;
+            colorVector[0] = srcColorMatrix[4] / 255.0f;
+            colorVector[1] = srcColorMatrix[9] / 255.0f;
+            colorVector[2] = srcColorMatrix[14] / 255.0f;
+            colorVector[3] = srcColorMatrix[19] / 255.0f;
+        } else {
+            LOG_ALWAYS_FATAL("unsupported ColorFilter");
+        }
+    } else {
+        mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
+    }
+}
+
+GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
+        const SkPaint* paint, float alphaScale) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = &texture;
+    mOutGlop->fill.textureFilter = PaintUtils::getFilter(paint);
+
+    if (paint) {
+        int color = paint->getColor();
+        SkShader* shader = paint->getShader();
+
+        if (!isAlphaMaskTexture) {
+            // Texture defines color, so disable shaders, and reset all non-alpha color channels
+            color |= 0x00FFFFFF;
+            shader = nullptr;
+        }
+        setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()),
+                shader, paint->getColorFilter());
+    } else {
+        mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
+
+        const bool SWAP_SRC_DST = false;
+        if (alphaScale < 1.0f
+                || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+                || texture.blend
+                || mOutGlop->roundRectClipState) {
+            Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+                    &mOutGlop->blend.src, &mOutGlop->blend.dst);
+        } else {
+            mOutGlop->blend = { GL_ZERO, GL_ZERO };
+        }
+    }
+
+    if (isAlphaMaskTexture) {
+        mDescription.modulate = mOutGlop->fill.color.a < 1.0f
+                || mOutGlop->fill.color.r > 0.0f
+                || mOutGlop->fill.color.g > 0.0f
+                || mOutGlop->fill.color.b > 0.0f;
+    } else {
+        mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    }
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = nullptr;
+    mOutGlop->fill.textureFilter = GL_NEAREST;
+
+    setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+            paint.getShader(), paint.getColorFilter());
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Transform
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setTransformClip(const Matrix4& ortho,
+        const Matrix4& transform, bool fudgingOffset) {
+    TRIGGER_STAGE(kTransformStage);
+
+    mOutGlop->transform.ortho.load(ortho);
+    mOutGlop->transform.canvas.load(transform);
+    mOutGlop->transform.fudgingOffset = fudgingOffset;
+    return *this;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// ModelView
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
+    TRIGGER_STAGE(kModelViewStage);
+
+    mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
+    mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+    mOutGlop->bounds = destination;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) {
+    TRIGGER_STAGE(kModelViewStage);
+    REQUIRE_STAGES(kTransformStage | kFillStage);
+
+    float left = destination.left;
+    float top = destination.top;
+
+    const Matrix4& canvasTransform = mOutGlop->transform.canvas;
+    if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+        const float translateX = canvasTransform.getTranslateX();
+        const float translateY = canvasTransform.getTranslateY();
+
+        left = (int) floorf(left + translateX + 0.5f) - translateX;
+        top = (int) floorf(top + translateY + 0.5f) - translateY;
+        mOutGlop->fill.textureFilter = GL_NEAREST;
+    }
+
+    mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
+    mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+    mOutGlop->bounds = destination;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
+    TRIGGER_STAGE(kModelViewStage);
+
+    mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+    mOutGlop->bounds = source;
+    mOutGlop->bounds.translate(offsetX, offsetY);
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
+    TRIGGER_STAGE(kRoundRectClipStage);
+
+    mOutGlop->roundRectClipState = roundRectClipState;
+    mDescription.hasRoundRectClip = roundRectClipState != nullptr;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Build
+////////////////////////////////////////////////////////////////////////////////
+
+void GlopBuilder::build() {
+    REQUIRE_STAGES(kAllStages);
+
+    mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+    mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
+
+    // duplicates ProgramCache's definition of color uniform presence
+    const bool singleColor = !mDescription.hasTexture
+            && !mDescription.hasExternalTexture
+            && !mDescription.hasGradient
+            && !mDescription.hasBitmap;
+    mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
new file mode 100644
index 0000000..04d421c
--- /dev/null
+++ b/libs/hwui/GlopBuilder.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_GLOPBUILDER_H
+#define RENDERSTATE_GLOPBUILDER_H
+
+#include "OpenGLRenderer.h"
+#include "Program.h"
+#include "utils/Macros.h"
+
+class SkPaint;
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+struct Glop;
+class Matrix4;
+class RenderState;
+class Texture;
+class VertexBuffer;
+
+class GlopBuilder {
+    PREVENT_COPY_AND_ASSIGN(GlopBuilder);
+public:
+    GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
+
+    GlopBuilder& setMeshUnitQuad();
+    GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper, bool isAlphaMaskTexture);
+    GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
+    GlopBuilder& setMeshIndexedQuads(void* vertexData, int quadCount);
+
+    GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale);
+    GlopBuilder& setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
+            const SkPaint* paint, float alphaScale);
+
+    GlopBuilder& setTransformClip(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
+
+    GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
+    GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination);
+    GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
+
+    GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
+
+    void build();
+private:
+    void setFill(int color, float alphaScale, SkXfermode::Mode mode,
+            const SkShader* shader, const SkColorFilter* colorFilter);
+
+    enum StageFlags {
+        kInitialStage = 0,
+        kMeshStage = 1 << 0,
+        kTransformStage = 1 << 1,
+        kModelViewStage = 1 << 2,
+        kFillStage = 1 << 3,
+        kRoundRectClipStage = 1 << 4,
+        kAllStages = kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
+    } mStageFlags;
+
+    ProgramDescription mDescription;
+    RenderState& mRenderState;
+    Caches& mCaches;
+    Glop* mOutGlop;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_GLOPBUILDER_H
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 0987d9b..fb4c785 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -62,9 +62,12 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-GradientCache::GradientCache():
-        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
+GradientCache::GradientCache(Extensions& extensions)
+        : mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity)
+        , mSize(0)
+        , mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE))
+        , mUseFloatTexture(extensions.hasFloatTextures())
+        , mHasNpot(extensions.hasNPot()){
     char property[PROPERTY_VALUE_MAX];
     if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting gradient cache size to %sMB", property);
@@ -76,16 +79,6 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
 
     mCache.setOnEntryRemovedListener(this);
-
-    const Extensions& extensions = Extensions::getInstance();
-    mUseFloatTexture = extensions.hasFloatTextures();
-    mHasNpot = extensions.hasNPot();
-}
-
-GradientCache::GradientCache(uint32_t maxByteSize):
-        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(maxByteSize) {
-    mCache.setOnEntryRemovedListener(this);
 }
 
 GradientCache::~GradientCache() {
@@ -285,7 +278,7 @@
     memcpy(pixels + rowBytes, pixels, rowBytes);
 
     glGenTextures(1, &texture->id);
-    Caches::getInstance().bindTexture(texture->id);
+    Caches::getInstance().textureState().bindTexture(texture->id);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
     if (mUseFloatTexture) {
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 9176c76..08319ea 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HWUI_GRADIENT_CACHE_H
 #define ANDROID_HWUI_GRADIENT_CACHE_H
 
+#include <memory>
+
 #include <GLES3/gl3.h>
 
 #include <SkShader.h>
@@ -102,8 +104,7 @@
  */
 class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
 public:
-    GradientCache();
-    GradientCache(uint32_t maxByteSize);
+    GradientCache(Extensions& extensions);
     ~GradientCache();
 
     /**
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index edf3930..a31c546 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -39,7 +39,7 @@
     } else {
         // Create a 2D texture to sample from the EGLImage
         glGenTextures(1, &mTexture);
-        Caches::getInstance().bindTexture(mTexture);
+        Caches::getInstance().textureState().bindTexture(mTexture);
         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
 
         GLenum status = GL_NO_ERROR;
@@ -54,7 +54,7 @@
         eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage);
         mImage = EGL_NO_IMAGE_KHR;
 
-        Caches::getInstance().deleteTexture(mTexture);
+        Caches::getInstance().textureState().deleteTexture(mTexture);
         mTexture = 0;
     }
 }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index ee6154f..7a026ef 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -68,15 +68,23 @@
 }
 
 Layer::~Layer() {
-    renderState.requireGLContext();
     renderState.unregisterLayer(this);
     SkSafeUnref(colorFilter);
-    removeFbo();
-    deleteTexture();
+
+    if (stencil || fbo || texture.id) {
+        renderState.requireGLContext();
+        removeFbo();
+        deleteTexture();
+    }
 
     delete[] mesh;
 }
 
+void Layer::onGlContextLost() {
+    removeFbo();
+    deleteTexture();
+}
+
 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
     return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
 }
@@ -126,7 +134,7 @@
     setSize(desiredWidth, desiredHeight);
 
     if (fbo) {
-        caches.activeTexture(0);
+        caches.textureState().activateTexture(0);
         bindTexture();
         allocateTexture();
 
@@ -187,7 +195,7 @@
 
 void Layer::bindTexture() const {
     if (texture.id) {
-        caches.bindTexture(renderTarget, texture.id);
+        caches.textureState().bindTexture(renderTarget, texture.id);
     }
 }
 
@@ -211,7 +219,7 @@
 }
 
 void Layer::clearTexture() {
-    caches.unbindTexture(texture.id);
+    caches.textureState().unbindTexture(texture.id);
     texture.id = 0;
 }
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 3b4f293..84ff021 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -288,6 +288,12 @@
     void postDecStrong();
 
     /**
+     * Lost the GL context but the layer is still around, mark it invalid internally
+     * so the dtor knows not to do any GL work
+     */
+    void onGlContextLost();
+
+    /**
      * Bounds of the layer.
      */
     Rect layer;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 076251f..b4b14e8 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -196,7 +196,7 @@
         return nullptr;
     }
 
-    caches.activeTexture(0);
+    caches.textureState().activateTexture(0);
     Layer* layer = caches.layerCache.get(renderState, width, height);
     if (!layer) {
         ALOGW("Could not obtain a layer");
@@ -283,7 +283,7 @@
     layer->region.clear();
     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
 
-    Caches::getInstance().activeTexture(0);
+    Caches::getInstance().textureState().activateTexture(0);
     layer->generateTexture();
 
     return layer;
@@ -337,7 +337,7 @@
     if (fbo) {
         // If possible, discard any enqueud operations on deferred
         // rendering architectures
-        if (Extensions::getInstance().hasDiscardFramebuffer()) {
+        if (Caches::getInstance().extensions().hasDiscardFramebuffer()) {
             GLuint previousFbo = renderState.getFramebuffer();
             if (fbo != previousFbo) {
                 renderState.bindFramebuffer(fbo);
@@ -412,8 +412,8 @@
         glGenTextures(1, &texture);
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        caches.activeTexture(0);
-        caches.bindTexture(texture);
+        caches.textureState().activateTexture(0);
+        caches.textureState().bindTexture(texture);
 
         glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
 
@@ -475,7 +475,7 @@
         renderState.bindFramebuffer(previousFbo);
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
-        caches.deleteTexture(texture);
+        caches.textureState().deleteTexture(texture);
         caches.fboCache.put(fbo);
         renderState.setViewport(previousViewportWidth, previousViewportHeight);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 0844cb6..0841124 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
-
 #include "OpenGLRenderer.h"
 
 #include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
-#include "Fence.h"
 #include "GammaFontRenderer.h"
+#include "Glop.h"
+#include "GlopBuilder.h"
 #include "Patch.h"
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "RenderNode.h"
+#include "renderstate/MeshState.h"
 #include "renderstate/RenderState.h"
 #include "ShadowTessellator.h"
 #include "SkiaShader.h"
@@ -57,69 +57,15 @@
     #define EVENT_LOGD(...)
 #endif
 
+#define USE_GLOPS true
+
 namespace android {
 namespace uirenderer {
 
-static GLenum getFilter(const SkPaint* paint) {
-    if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
-        return GL_LINEAR;
-    }
-    return GL_NEAREST;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Globals
 ///////////////////////////////////////////////////////////////////////////////
 
-/**
- * Structure mapping Skia xfermodes to OpenGL blending factors.
- */
-struct Blender {
-    SkXfermode::Mode mode;
-    GLenum src;
-    GLenum dst;
-}; // struct Blender
-
-// In this array, the index of each Blender equals the value of the first
-// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
-static const Blender gBlends[] = {
-    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
-    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
-    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
-    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
-    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
-    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
-    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
-    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
-    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
-};
-
-// This array contains the swapped version of each SkXfermode. For instance
-// this array's SrcOver blending mode is actually DstOver. You can refer to
-// createLayer() for more information on the purpose of this array.
-static const Blender gBlendsSwap[] = {
-    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
-    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
-    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
-    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
-    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
-    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
-    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
-    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
-    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
-    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
-};
 
 ///////////////////////////////////////////////////////////////////////////////
 // Functions
@@ -137,7 +83,6 @@
 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
         : mState(*this)
         , mCaches(Caches::getInstance())
-        , mExtensions(Extensions::getInstance())
         , mRenderState(renderState)
         , mFrameStarted(false)
         , mScissorOptimizationDisabled(false)
@@ -152,7 +97,7 @@
     memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
 
-    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
+    memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices));
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -186,8 +131,6 @@
 void OpenGLRenderer::onViewportInitialized() {
     glDisable(GL_DITHER);
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
-    glEnableVertexAttribArray(Program::kBindingPosition);
     mFirstFrameAfterResize = true;
 }
 
@@ -234,7 +177,7 @@
     // for each layer and wait until the first drawing command
     // to start the frame
     if (currentSnapshot()->fbo == 0) {
-        syncState();
+        mRenderState.blend().syncEnabled();
         updateLayers();
     } else {
         startFrame();
@@ -245,7 +188,7 @@
     // If we know that we are going to redraw the entire framebuffer,
     // perform a discard to let the driver know we don't need to preserve
     // the back buffer for this frame.
-    if (mExtensions.hasDiscardFramebuffer() &&
+    if (mCaches.extensions().hasDiscardFramebuffer() &&
             left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
         const bool isFbo = onGetTargetFbo() == 0;
         const GLenum attachments[] = {
@@ -267,14 +210,6 @@
     mRenderState.scissor().reset();
 }
 
-void OpenGLRenderer::syncState() {
-    if (mCaches.blend) {
-        glEnable(GL_BLEND);
-    } else {
-        glDisable(GL_BLEND);
-    }
-}
-
 void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
     if (!mSuppressTiling) {
         const Snapshot* snapshot = currentSnapshot();
@@ -436,22 +371,22 @@
                 clip->bottom - clip->top);
 
         // 1x overdraw
-        mCaches.stencil.enableDebugTest(2);
+        mRenderState.stencil().enableDebugTest(2);
         drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
 
         // 2x overdraw
-        mCaches.stencil.enableDebugTest(3);
+        mRenderState.stencil().enableDebugTest(3);
         drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
 
         // 3x overdraw
-        mCaches.stencil.enableDebugTest(4);
+        mRenderState.stencil().enableDebugTest(4);
         drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
 
         // 4x overdraw and higher
-        mCaches.stencil.enableDebugTest(4, true);
+        mRenderState.stencil().enableDebugTest(4, true);
         drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
 
-        mCaches.stencil.disable();
+        mRenderState.stencil().disable();
     }
 }
 
@@ -559,11 +494,11 @@
 
 void OpenGLRenderer::flushLayerUpdates() {
     ATRACE_NAME("Update HW Layers");
-    syncState();
+    mRenderState.blend().syncEnabled();
     updateLayers();
     flushLayers();
     // Wait for all the layer updates to be executed
-    AutoFence fence;
+    glFinish();
 }
 
 void OpenGLRenderer::markLayersAsBuildLayers() {
@@ -756,7 +691,7 @@
         return false;
     }
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
     if (!layer) {
         return false;
@@ -894,9 +829,9 @@
         layer->setAlpha(255);
     }
 
-    mCaches.unbindMeshBuffer();
+    mRenderState.meshState().unbindMeshBuffer();
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
     // When the layer is stored in an FBO, we can save a bit of fillrate by
     // drawing only the dirty region
@@ -963,7 +898,7 @@
     setupDrawTextureTransformUniforms(layer->getTexTransform());
     setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -1005,7 +940,7 @@
         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
                 layer->getTexture(), &layerPaint, blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
 
         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     }
@@ -1171,7 +1106,7 @@
 
         numQuads++;
 
-        if (numQuads >= gMaxNumberOfQuads) {
+        if (numQuads >= kMaxNumberOfQuads) {
             DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
                     GL_UNSIGNED_SHORT, nullptr));
             numQuads = 0;
@@ -1264,7 +1199,7 @@
 void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
     GLsizei elementsCount = quadsCount * 6;
     while (elementsCount > 0) {
-        GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+        GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
 
         setupDrawIndexedVertices(&mesh[0].x);
         glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
@@ -1445,7 +1380,8 @@
         endTiling();
 
         RenderBuffer* buffer = mCaches.renderBufferCache.get(
-                Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
+                Stencil::getSmallestStencilFormat(),
+                layer->getWidth(), layer->getHeight());
         layer->setStencilRenderBuffer(buffer);
 
         startTiling(layer->clipRect, layer->layer.getHeight());
@@ -1537,7 +1473,7 @@
                 incrementThreshold = 0;
             }
 
-            mCaches.stencil.enableWrite(incrementThreshold);
+            mRenderState.stencil().enableWrite(incrementThreshold);
 
             // Clean and update the stencil, but first make sure we restrict drawing
             // to the region's bounds
@@ -1547,7 +1483,7 @@
                 setScissorFromClip();
             }
 
-            mCaches.stencil.clear();
+            mRenderState.stencil().clear();
 
             // stash and disable the outline clip state, since stencil doesn't account for outline
             bool storedSkipOutlineClip = mSkipOutlineClip;
@@ -1571,7 +1507,7 @@
             if (resetScissor) mRenderState.scissor().setEnabled(false);
             mSkipOutlineClip = storedSkipOutlineClip;
 
-            mCaches.stencil.enableTest(incrementThreshold);
+            mRenderState.stencil().enableTest(incrementThreshold);
 
             // Draw the region used to generate the stencil if the appropriate debug
             // mode is enabled
@@ -1584,7 +1520,7 @@
             }
         } else {
             EVENT_LOGD("setStencilFromClip - disabling");
-            mCaches.stencil.disable();
+            mRenderState.stencil().disable();
         }
     }
 }
@@ -1631,6 +1567,24 @@
 #endif
 }
 
+void OpenGLRenderer::renderGlop(const Glop& glop) {
+    if (mState.getDirtyClip()) {
+        if (mRenderState.scissor().isEnabled()) {
+            setScissorFromClip();
+        }
+
+        setStencilFromClip();
+    }
+    mRenderState.render(glop);
+
+    if (!mRenderState.stencil().isWriteEnabled()) {
+        // TODO: specify more clearly when a draw should dirty the layer.
+        // is writing to the stencil the only time we should ignore this?
+        dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+        mDirty = true;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Drawing commands
 ///////////////////////////////////////////////////////////////////////////////
@@ -1653,15 +1607,15 @@
 
     mSetShaderColor = false;
     mColorSet = false;
-    mColorA = mColorR = mColorG = mColorB = 0.0f;
+    mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
     mTextureUnit = 0;
     mTrackDirtyRegions = true;
 
     // Enable debug highlight when what we're about to draw is tested against
     // the stencil buffer and if stencil highlight debugging is on
-    mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
-            mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
-            mCaches.stencil.isTestEnabled();
+    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
+            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
+            && mRenderState.stencil().isTestEnabled();
 }
 
 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1680,7 +1634,7 @@
 }
 
 void OpenGLRenderer::setupDrawNoTexture() {
-    mCaches.disableTexCoordsVertexArray();
+    mRenderState.meshState().disableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
@@ -1689,21 +1643,21 @@
 }
 
 void OpenGLRenderer::setupDrawColor(int color, int alpha) {
-    mColorA = alpha / 255.0f;
-    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
-    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
-    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
+    mColor.a = alpha / 255.0f;
+    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
+    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
+    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
     mColorSet = true;
-    mSetShaderColor = mDescription.setColorModulate(mColorA);
+    mSetShaderColor = mDescription.setColorModulate(mColor.a);
 }
 
 void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
-    mColorA = alpha / 255.0f;
-    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
-    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
-    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
+    mColor.a = alpha / 255.0f;
+    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
+    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
+    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
     mColorSet = true;
-    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
+    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
 }
 
 void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
@@ -1711,17 +1665,17 @@
 }
 
 void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
-    mColorA = a;
-    mColorR = r;
-    mColorG = g;
-    mColorB = b;
+    mColor.a = a;
+    mColor.r = r;
+    mColor.g = g;
+    mColor.b = b;
     mColorSet = true;
     mSetShaderColor = mDescription.setColorModulate(a);
 }
 
 void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
     if (shader != nullptr) {
-        SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
+        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
     }
 }
 
@@ -1741,8 +1695,8 @@
 
 void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
     if (mColorSet && mode == SkXfermode::kClear_Mode) {
-        mColorA = 1.0f;
-        mColorR = mColorG = mColorB = 0.0f;
+        mColor.a = 1.0f;
+        mColor.r = mColor.g = mColor.b = 0.0f;
         mSetShaderColor = mDescription.modulate = true;
     }
 }
@@ -1755,7 +1709,7 @@
     // TODO: check shader blending, once we have shader drawing support for layers.
     bool blend = layer->isBlend()
             || getLayerAlpha(layer) < 1.0f
-            || (mColorSet && mColorA < 1.0f)
+            || (mColorSet && mColor.a < 1.0f)
             || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
@@ -1765,27 +1719,27 @@
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
-    blend |= (mColorSet && mColorA < 1.0f) ||
-            (getShader(paint) && !getShader(paint)->isOpaque()) ||
-            PaintUtils::isBlendedColorFilter(getColorFilter(paint));
+    blend |= (mColorSet && mColor.a < 1.0f)
+            || (getShader(paint) && !getShader(paint)->isOpaque())
+            || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
 void OpenGLRenderer::setupDrawProgram() {
-    useProgram(mCaches.programCache.get(mDescription));
+    mCaches.setProgram(mDescription);
     if (mDescription.hasRoundRectClip) {
         // TODO: avoid doing this repeatedly, stashing state pointer in program
         const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
         const Rect& innerRect = state->innerRect;
-        glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
+        glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
                 innerRect.left, innerRect.top,
                 innerRect.right, innerRect.bottom);
-        glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
+        glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
                 1, GL_FALSE, &state->matrix.data[0]);
 
         // add half pixel to round out integer rect space to cover pixel centers
         float roundedOutRadius = state->radius + 0.5f;
-        glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
+        glUniform1f(mCaches.program().getUniform("roundRectRadius"),
                 roundedOutRadius);
     }
 }
@@ -1803,7 +1757,8 @@
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
     const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
-    mCaches.currentProgram->set(writableSnapshot()->getOrthoMatrix(),
+
+    mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
             mModelViewMatrix, transformMatrix, offset);
     if (dirty && mTrackDirtyRegions) {
         if (!ignoreTransform) {
@@ -1816,13 +1771,13 @@
 
 void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
     if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
-        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
+        mCaches.program().setColor(mColor);
     }
 }
 
 void OpenGLRenderer::setupDrawPureColorUniforms() {
     if (mSetShaderColor) {
-        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
+        mCaches.program().setColor(mColor);
     }
 }
 
@@ -1841,7 +1796,8 @@
         mModelViewMatrix.load(modelViewWithoutTransform);
     }
 
-    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
+    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
+            mCaches.extensions(), *shader);
 }
 
 void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
@@ -1857,7 +1813,7 @@
         const GLfloat r = a * SkColorGetR(color) / 255.0f;
         const GLfloat g = a * SkColorGetG(color) / 255.0f;
         const GLfloat b = a * SkColorGetB(color) / 255.0f;
-        glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
+        glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
         return;
     }
 
@@ -1878,9 +1834,9 @@
         colorVector[2] = srcColorMatrix[14] / 255.0f;
         colorVector[3] = srcColorMatrix[19] / 255.0f;
 
-        glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
+        glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
                 GL_FALSE, colorMatrix);
-        glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
+        glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
         return;
     }
 
@@ -1888,25 +1844,25 @@
 }
 
 void OpenGLRenderer::setupDrawTextGammaUniforms() {
-    mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
+    mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
 }
 
 void OpenGLRenderer::setupDrawSimpleMesh() {
-    bool force = mCaches.bindMeshBuffer();
-    mCaches.bindPositionVertexPointer(force, nullptr);
-    mCaches.unbindIndicesBuffer();
+    bool force = mRenderState.meshState().bindMeshBuffer();
+    mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
+    mRenderState.meshState().unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
-    if (texture) bindTexture(texture);
+    if (texture) mCaches.textureState().bindTexture(texture);
     mTextureUnit++;
-    mCaches.enableTexCoordsVertexArray();
+    mRenderState.meshState().enableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
-    bindExternalTexture(texture);
+    mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
     mTextureUnit++;
-    mCaches.enableTexCoordsVertexArray();
+    mRenderState.meshState().enableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawTextureTransform() {
@@ -1914,7 +1870,7 @@
 }
 
 void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
-    glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
+    glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
             GL_FALSE, &transform.data[0]);
 }
 
@@ -1922,35 +1878,35 @@
         const GLvoid* texCoords, GLuint vbo) {
     bool force = false;
     if (!vertices || vbo) {
-        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+        force = mRenderState.meshState().bindMeshBuffer(vbo);
     } else {
-        force = mCaches.unbindMeshBuffer();
+        force = mRenderState.meshState().unbindMeshBuffer();
     }
 
-    mCaches.bindPositionVertexPointer(force, vertices);
-    if (mCaches.currentProgram->texCoords >= 0) {
-        mCaches.bindTexCoordsVertexPointer(force, texCoords);
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
+    if (mCaches.program().texCoords >= 0) {
+        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
     }
 
-    mCaches.unbindIndicesBuffer();
+    mRenderState.meshState().unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
         const GLvoid* texCoords, const GLvoid* colors) {
-    bool force = mCaches.unbindMeshBuffer();
+    bool force = mRenderState.meshState().unbindMeshBuffer();
     GLsizei stride = sizeof(ColorTextureVertex);
 
-    mCaches.bindPositionVertexPointer(force, vertices, stride);
-    if (mCaches.currentProgram->texCoords >= 0) {
-        mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
+    if (mCaches.program().texCoords >= 0) {
+        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
     }
-    int slot = mCaches.currentProgram->getAttrib("colors");
+    int slot = mCaches.program().getAttrib("colors");
     if (slot >= 0) {
         glEnableVertexAttribArray(slot);
         glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
     }
 
-    mCaches.unbindIndicesBuffer();
+    mRenderState.meshState().unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
@@ -1958,24 +1914,24 @@
     bool force = false;
     // If vbo is != 0 we want to treat the vertices parameter as an offset inside
     // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
-    // use the default VBO found in Caches
+    // use the default VBO found in RenderState
     if (!vertices || vbo) {
-        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+        force = mRenderState.meshState().bindMeshBuffer(vbo);
     } else {
-        force = mCaches.unbindMeshBuffer();
+        force = mRenderState.meshState().unbindMeshBuffer();
     }
-    mCaches.bindQuadIndicesBuffer();
+    mRenderState.meshState().bindQuadIndicesBuffer();
 
-    mCaches.bindPositionVertexPointer(force, vertices);
-    if (mCaches.currentProgram->texCoords >= 0) {
-        mCaches.bindTexCoordsVertexPointer(force, texCoords);
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
+    if (mCaches.program().texCoords >= 0) {
+        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
     }
 }
 
 void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
-    bool force = mCaches.unbindMeshBuffer();
-    mCaches.bindQuadIndicesBuffer();
-    mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
+    bool force = mRenderState.meshState().unbindMeshBuffer();
+    mRenderState.meshState().bindQuadIndicesBuffer();
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2013,29 +1969,41 @@
     }
 }
 
-void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top,
-        const SkPaint* paint) {
-    float x = left;
-    float y = top;
+void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
+    if (USE_GLOPS && (!paint || !paint->getShader())) {
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshTexturedUnitQuad(texture->uvMapper, true)
+                .setFillTexturePaint(*texture, true, paint, currentSnapshot()->alpha)
+                .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    float x = 0;
+    float y = 0;
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
     bool ignoreTransform = false;
     if (currentTransform()->isPureTranslate()) {
-        x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
-        y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
+        x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
+        y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
         ignoreTransform = true;
 
         texture->setFilter(GL_NEAREST, true);
     } else {
-        texture->setFilter(getFilter(paint), true);
+        texture->setFilter(PaintUtils::getFilter(paint), true);
     }
 
     // No need to check for a UV mapper on the texture object, only ARGB_8888
     // bitmaps get packed in the atlas
     drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-            paint, (GLvoid*) nullptr, (GLvoid*) gMeshTextureOffset,
-            GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+            paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
+            GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
 }
 
 /**
@@ -2046,14 +2014,14 @@
 void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
         int bitmapCount, TextureVertex* vertices, bool pureTranslate,
         const Rect& bounds, const SkPaint* paint) {
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
     if (!texture) return;
 
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
+    texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
 
     const float x = (int) floorf(bounds.left + 0.5f);
     const float y = (int) floorf(bounds.top + 0.5f);
@@ -2077,15 +2045,15 @@
         return;
     }
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Texture* texture = getTexture(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, 0, 0, paint);
+        drawAlphaBitmap(texture, paint);
     } else {
-        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
+        drawTextureRect(texture, paint);
     }
 
     mDirty = true;
@@ -2118,7 +2086,7 @@
         colors = tempColors.get();
     }
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
     const UvMapper& mapper(getMapper(texture));
 
@@ -2170,7 +2138,7 @@
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(getFilter(paint), true);
+    texture->setFilter(PaintUtils::getFilter(paint), true);
 
     int alpha;
     SkXfermode::Mode mode;
@@ -2189,7 +2157,7 @@
     setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
+    setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
@@ -2197,7 +2165,7 @@
 
     glDrawArrays(GL_TRIANGLES, 0, count);
 
-    int slot = mCaches.currentProgram->getAttrib("colors");
+    int slot = mCaches.program().getAttrib("colors");
     if (slot >= 0) {
         glDisableVertexAttribArray(slot);
     }
@@ -2213,7 +2181,7 @@
         return;
     }
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Texture* texture = getTexture(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -2228,7 +2196,7 @@
 
     getMapper(texture).map(u1, v1, u2, v2);
 
-    mCaches.unbindMeshBuffer();
+    mRenderState.meshState().unbindMeshBuffer();
     resetDrawTextureTexCoords(u1, v1, u2, v2);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -2253,10 +2221,10 @@
         dstLeft = x;
         dstTop = y;
 
-        texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
+        texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
         ignoreTransform = true;
     } else {
-        texture->setFilter(getFilter(paint), true);
+        texture->setFilter(PaintUtils::getFilter(paint), true);
     }
 
     if (CC_UNLIKELY(useScaleTransform)) {
@@ -2275,12 +2243,12 @@
         drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
                 texture->id, paint,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
     } else {
         drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
                 texture->id, paint, texture->blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
     }
 
     if (CC_UNLIKELY(useScaleTransform)) {
@@ -2313,7 +2281,7 @@
     }
 
     if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
-        mCaches.activeTexture(0);
+        mCaches.textureState().activateTexture(0);
         Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
         if (!texture) return;
         const AutoTexture autoCleanup(texture);
@@ -2367,7 +2335,7 @@
  */
 void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
         TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -2390,17 +2358,33 @@
         return;
     }
 
+    if (USE_GLOPS && !paint->getShader()) {
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
+        bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
+        aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
+                .setFillPaint(*paint, currentSnapshot()->alpha)
+                .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
+                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
     Rect bounds(vertexBuffer.getBounds());
     bounds.translate(translateX, translateY);
     dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
 
     int color = paint->getColor();
-    bool isAA = paint->isAntiAlias();
+    bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
 
     setupDraw();
     setupDrawNoTexture();
     if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
-    setupDrawColor(color, ((color >> 24) & 0xFF) * writableSnapshot()->alpha);
+    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader(getShader(paint));
     setupDrawBlending(paint, isAA);
@@ -2412,35 +2396,27 @@
     setupDrawShaderUniforms(getShader(paint));
 
     const void* vertices = vertexBuffer.getBuffer();
-    mCaches.unbindMeshBuffer();
-    mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
-    mCaches.resetTexCoordsVertexPointer();
+    mRenderState.meshState().unbindMeshBuffer();
+    mRenderState.meshState().bindPositionVertexPointer(true, vertices,
+            isAA ? kAlphaVertexStride : kVertexStride);
+    mRenderState.meshState().resetTexCoordsVertexPointer();
 
     int alphaSlot = -1;
     if (isAA) {
-        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
-        alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
+        void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
+        alphaSlot = mCaches.program().getAttrib("vtxAlpha");
         // TODO: avoid enable/disable in back to back uses of the alpha attribute
         glEnableVertexAttribArray(alphaSlot);
-        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
+        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
     }
 
-    const VertexBuffer::Mode mode = vertexBuffer.getMode();
-    if (mode == VertexBuffer::kStandard) {
-        mCaches.unbindIndicesBuffer();
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
-    } else if (mode == VertexBuffer::kOnePolyRingShadow) {
-        mCaches.bindShadowIndicesBuffer();
-        glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT,
-                GL_UNSIGNED_SHORT, nullptr);
-    } else if (mode == VertexBuffer::kTwoPolyRingShadow) {
-        mCaches.bindShadowIndicesBuffer();
-        glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT,
-                GL_UNSIGNED_SHORT, nullptr);
-    } else if (mode == VertexBuffer::kIndices) {
-        mCaches.unbindIndicesBuffer();
+    if (meshFeatureFlags & VertexBuffer::kIndices) {
+        mRenderState.meshState().unbindIndicesBuffer();
         glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
                 GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
+    } else {
+        mRenderState.meshState().unbindIndicesBuffer();
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
     }
 
     if (isAA) {
@@ -2551,7 +2527,7 @@
     }
 
     if (p->getPathEffect() != nullptr) {
-        mCaches.activeTexture(0);
+        mCaches.textureState().activateTexture(0);
         const PathTexture* texture = mCaches.pathCache.getRoundRect(
                 right - left, bottom - top, rx, ry, p);
         drawShape(left, top, texture, p);
@@ -2569,7 +2545,7 @@
         return;
     }
     if (p->getPathEffect() != nullptr) {
-        mCaches.activeTexture(0);
+        mCaches.textureState().activateTexture(0);
         const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
         drawShape(x - radius, y - radius, texture, p);
     } else {
@@ -2592,7 +2568,7 @@
     }
 
     if (p->getPathEffect() != nullptr) {
-        mCaches.activeTexture(0);
+        mCaches.textureState().activateTexture(0);
         const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
         drawShape(left, top, texture, p);
     } else {
@@ -2616,7 +2592,7 @@
 
     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
     if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
-        mCaches.activeTexture(0);
+        mCaches.textureState().activateTexture(0);
         const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
                 startAngle, sweepAngle, useCenter, p);
         drawShape(left, top, texture, p);
@@ -2653,7 +2629,7 @@
         // only fill style is supported by drawConvexPath, since others have to handle joins
         if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
-            mCaches.activeTexture(0);
+            mCaches.textureState().activateTexture(0);
             const PathTexture* texture =
                     mCaches.pathCache.getRect(right - left, bottom - top, p);
             drawShape(left, top, texture, p);
@@ -2682,7 +2658,7 @@
 void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
         int bytesCount, int count, const float* positions,
         FontRenderer& fontRenderer, int alpha, float x, float y) {
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
     TextShadow textShadow;
     if (!getTextShadow(paint, &textShadow)) {
@@ -2720,9 +2696,9 @@
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms(getShader(paint));
-    setupDrawMesh(nullptr, (GLvoid*) gMeshTextureOffset);
+    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
@@ -2872,8 +2848,6 @@
     mState.setClippingRoundRect(allocator, rect, radius, highPriority);
 }
 
-
-
 void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
         const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
         DrawOpMode drawOpMode) {
@@ -2998,7 +2972,7 @@
 void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
     if (mState.currentlyIgnored()) return;
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
     const PathTexture* texture = mCaches.pathCache.get(path, paint);
     if (!texture) return;
@@ -3043,7 +3017,7 @@
     updateLayer(layer, true);
 
     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
@@ -3078,7 +3052,7 @@
             GLsizei elementsCount = layer->meshElementCount;
 
             while (elementsCount > 0) {
-                GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+                GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
 
                 setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
                 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
@@ -3156,9 +3130,9 @@
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms(getShader(paint));
-    setupDrawMesh(nullptr, (GLvoid*) gMeshTextureOffset);
+    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
 // Same values used by Skia
@@ -3257,12 +3231,6 @@
         return;
     }
 
-    int color = paint->getColor();
-    // If a shader is set, preserve only the alpha
-    if (getShader(paint)) {
-        color |= 0x00ffffff;
-    }
-
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
@@ -3292,6 +3260,26 @@
         return;
     }
 
+    if (USE_GLOPS && !paint->getShader()) {
+        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshIndexedQuads(&mesh[0], count / 4)
+                .setFillPaint(*paint, currentSnapshot()->alpha)
+                .setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    int color = paint->getColor();
+    // If a shader is set, preserve only the alpha
+    if (getShader(paint)) {
+        color |= 0x00ffffff;
+    }
+
     setupDraw();
     setupDrawNoTexture();
     setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
@@ -3317,6 +3305,21 @@
 
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
         const SkPaint* paint, bool ignoreTransform) {
+
+    if (USE_GLOPS && !paint->getShader()) {
+        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshUnitQuad()
+                .setFillPaint(*paint, currentSnapshot()->alpha)
+                .setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
     int color = paint->getColor();
     // If a shader is set, preserve only the alpha
     if (getShader(paint)) {
@@ -3337,15 +3340,27 @@
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawSimpleMesh();
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
-void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        Texture* texture, const SkPaint* paint) {
+void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
+    if (USE_GLOPS) {
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshTexturedUnitQuad(texture->uvMapper, false)
+                .setFillTexturePaint(*texture, false, paint, currentSnapshot()->alpha)
+                .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
     GLvoid* vertices = (GLvoid*) nullptr;
-    GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
+    GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
 
     if (texture->uvMapper) {
         vertices = &mMeshVertices[0].x;
@@ -3358,17 +3373,17 @@
     }
 
     if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-        const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
+        const float x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
+        const float y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
 
         texture->setFilter(GL_NEAREST, true);
         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
                 paint, texture->blend, vertices, texCoords,
-                GL_TRIANGLE_STRIP, gMeshCount, false, true);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
     } else {
-        texture->setFilter(getFilter(paint), true);
-        drawTextureMesh(left, top, right, bottom, texture->id, paint,
-                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
+        texture->setFilter(PaintUtils::getFilter(paint), true);
+        drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
+                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
     }
 
     if (texture->uvMapper) {
@@ -3463,7 +3478,7 @@
 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
         ProgramDescription& description, bool swapSrcDst) {
 
-    if (writableSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
+    if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
         blend = true;
         mDescription.hasRoundRectClip = true;
     }
@@ -3478,47 +3493,20 @@
         // If the blend mode cannot be implemented using shaders, fall
         // back to the default SrcOver blend mode instead
         if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
-            if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
+            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
                 description.framebufferMode = mode;
                 description.swapSrcDst = swapSrcDst;
 
-                if (mCaches.blend) {
-                    glDisable(GL_BLEND);
-                    mCaches.blend = false;
-                }
-
+                mRenderState.blend().disable();
                 return;
             } else {
                 mode = SkXfermode::kSrcOver_Mode;
             }
         }
-
-        if (!mCaches.blend) {
-            glEnable(GL_BLEND);
-        }
-
-        GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
-        GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
-
-        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
-            glBlendFunc(sourceMode, destMode);
-            mCaches.lastSrcMode = sourceMode;
-            mCaches.lastDstMode = destMode;
-        }
-    } else if (mCaches.blend) {
-        glDisable(GL_BLEND);
+        mRenderState.blend().enable(mode, swapSrcDst);
+    } else {
+        mRenderState.blend().disable();
     }
-    mCaches.blend = blend;
-}
-
-bool OpenGLRenderer::useProgram(Program* program) {
-    if (!program->isInUse()) {
-        if (mCaches.currentProgram != nullptr) mCaches.currentProgram->remove();
-        program->use();
-        mCaches.currentProgram = program;
-        return false;
-    }
-    return true;
 }
 
 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 94054ff..4f8a2ea 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -57,6 +57,7 @@
 namespace uirenderer {
 
 class DeferredDisplayState;
+struct Glop;
 class RenderState;
 class RenderNode;
 class TextSetupFunctor;
@@ -529,10 +530,11 @@
 
     CanvasState mState;
     Caches& mCaches;
-    Extensions& mExtensions; // TODO: move to RenderState
     RenderState& mRenderState;
 
 private:
+    void renderGlop(const Glop& glop);
+
     /**
      * Discards the content of the framebuffer if supported by the driver.
      * This method should be called at the beginning of a frame to optimize
@@ -541,12 +543,6 @@
     void discardFramebuffer(float left, float top, float right, float bottom);
 
     /**
-     * Ensures the state of the renderer is the same as the state of
-     * the GL context.
-     */
-    void syncState();
-
-    /**
      * Tells the GPU what part of the screen is about to be redrawn.
      * This method will use the current layer space clip rect.
      * This method needs to be invoked every time getTargetFbo() is
@@ -701,11 +697,9 @@
      * different compositing rules.
      *
      * @param texture The texture to draw with
-     * @param left The x coordinate of the bitmap
-     * @param top The y coordinate of the bitmap
      * @param paint The paint to render with
      */
-    void drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint);
+    void drawAlphaBitmap(Texture* texture, const SkPaint* paint);
 
     /**
      * Renders a strip of polygons with the specified paint, used for tessellated geometry.
@@ -734,18 +728,12 @@
     void drawConvexPath(const SkPath& path, const SkPaint* paint);
 
     /**
-     * Draws a textured rectangle with the specified texture. The specified coordinates
-     * are transformed by the current snapshot's transform matrix.
+     * Draws a textured rectangle with the specified texture.
      *
-     * @param left The left coordinate of the rectangle
-     * @param top The top coordinate of the rectangle
-     * @param right The right coordinate of the rectangle
-     * @param bottom The bottom coordinate of the rectangle
      * @param texture The texture to use
      * @param paint The paint containing the alpha, blending mode, etc.
      */
-    void drawTextureRect(float left, float top, float right, float bottom,
-            Texture* texture, const SkPaint* paint);
+    void drawTextureRect(Texture* texture, const SkPaint* paint);
 
     /**
      * Draws a textured mesh with the specified texture. If the indices are omitted,
@@ -852,22 +840,6 @@
     bool canSkipText(const SkPaint* paint) const;
 
     /**
-     * Binds the specified texture. The texture unit must have been selected
-     * prior to calling this method.
-     */
-    inline void bindTexture(GLuint texture) {
-        mCaches.bindTexture(texture);
-    }
-
-    /**
-     * Binds the specified EGLImage texture. The texture unit must have been selected
-     * prior to calling this method.
-     */
-    inline void bindExternalTexture(GLuint texture) {
-        mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
-    }
-
-    /**
      * Enable or disable blending as necessary. This function sets the appropriate
      * blend function based on the specified xfermode.
      */
@@ -875,18 +847,6 @@
             bool swapSrcDst = false);
 
     /**
-     * Use the specified program with the current GL context. If the program is already
-     * in use, it will not be bound again. If it is not in use, the current program is
-     * marked unused and the specified program becomes used and becomes the new
-     * current program.
-     *
-     * @param program The program to use
-     *
-     * @return true If the specified program was already in use, false otherwise.
-     */
-    inline bool useProgram(Program* program);
-
-    /**
      * Invoked before any drawing operation. This sets required state.
      */
     void setupDraw(bool clear = true);
@@ -1042,7 +1002,7 @@
     ProgramDescription mDescription;
     // Color description
     bool mColorSet;
-    float mColorA, mColorR, mColorG, mColorB;
+    FloatColor mColor;
     // Indicates that the shader should get a color
     bool mSetShaderColor;
     // Current texture unit
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index eb88bc0..af403b4 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -23,6 +23,7 @@
 #include "Patch.h"
 #include "PatchCache.h"
 #include "Properties.h"
+#include "renderstate/RenderState.h"
 
 namespace android {
 namespace uirenderer {
@@ -31,9 +32,13 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-PatchCache::PatchCache():
-        mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
-        mMeshBuffer(0), mFreeBlocks(nullptr), mGenerationId(0) {
+PatchCache::PatchCache(RenderState& renderState)
+        : mRenderState(renderState)
+        , mSize(0)
+        , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
+        , mMeshBuffer(0)
+        , mFreeBlocks(nullptr)
+        , mGenerationId(0) {
     char property[PROPERTY_VALUE_MAX];
     if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting patch cache size to %skB", property);
@@ -48,15 +53,15 @@
     clear();
 }
 
-void PatchCache::init(Caches& caches) {
+void PatchCache::init() {
     bool created = false;
     if (!mMeshBuffer) {
         glGenBuffers(1, &mMeshBuffer);
         created = true;
     }
 
-    caches.bindMeshBuffer(mMeshBuffer);
-    caches.resetVertexPointers();
+    mRenderState.meshState().bindMeshBuffer(mMeshBuffer);
+    mRenderState.meshState().resetVertexPointers();
 
     if (created) {
         createVertexBuffer();
@@ -85,7 +90,7 @@
     clearCache();
 
     if (mMeshBuffer) {
-        Caches::getInstance().unbindMeshBuffer();
+        mRenderState.meshState().unbindMeshBuffer();
         glDeleteBuffers(1, &mMeshBuffer);
         mMeshBuffer = 0;
         mSize = 0;
@@ -187,7 +192,7 @@
  */
 void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
     // This call ensures the VBO exists and that it is bound
-    init(Caches::getInstance());
+    init();
 
     // If we're running out of space, let's clear the entire cache
     uint32_t size = newMesh->getSize();
@@ -219,7 +224,7 @@
 
     // Copy the 9patch mesh in the VBO
     newMesh->offset = (GLintptr) (block->offset);
-    newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
+    newMesh->textureOffset = newMesh->offset + kMeshTextureOffset;
     glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
 
     // Remove the block since we've used it entirely
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 4cb5338..e038720 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -51,9 +51,9 @@
 
 class PatchCache {
 public:
-    PatchCache();
+    PatchCache(RenderState& renderState);
     ~PatchCache();
-    void init(Caches& caches);
+    void init();
 
     const Patch* get(const AssetAtlas::Entry* entry,
             const uint32_t bitmapWidth, const uint32_t bitmapHeight,
@@ -168,6 +168,7 @@
     void dumpFreeBlocks(const char* prefix);
 #endif
 
+    RenderState& mRenderState;
     uint32_t mMaxSize;
     uint32_t mSize;
 
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index c564b87..e2caf8b 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -31,7 +31,6 @@
 #include "PathCache.h"
 
 #include "thread/Signal.h"
-#include "thread/Task.h"
 #include "thread/TaskProcessor.h"
 
 namespace android {
@@ -231,7 +230,7 @@
         }
 
         if (texture->id) {
-            Caches::getInstance().deleteTexture(texture->id);
+            Caches::getInstance().textureState().deleteTexture(texture->id);
         }
         delete texture;
     }
@@ -313,7 +312,7 @@
 
     glGenTextures(1, &texture->id);
 
-    Caches::getInstance().bindTexture(texture->id);
+    Caches::getInstance().textureState().bindTexture(texture->id);
     // Textures are Alpha8
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
@@ -493,7 +492,9 @@
         if (mProcessor == nullptr) {
             mProcessor = new PathProcessor(Caches::getInstance());
         }
-        mProcessor->add(task);
+        if (!mProcessor->add(task)) {
+            mProcessor->process(task);
+        }
     }
 }
 
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index ecd3712..7378018 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -17,21 +17,22 @@
 #ifndef ANDROID_HWUI_PATH_CACHE_H
 #define ANDROID_HWUI_PATH_CACHE_H
 
-#include <GLES2/gl2.h>
+#include "Debug.h"
+#include "Texture.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
+#include "utils/Macros.h"
+#include "utils/Pair.h"
 
+#include <GLES2/gl2.h>
+#include <SkPath.h>
 #include <utils/LruCache.h>
 #include <utils/Mutex.h>
 #include <utils/Vector.h>
 
-#include "Debug.h"
-#include "Texture.h"
-#include "utils/Macros.h"
-#include "utils/Pair.h"
-
 class SkBitmap;
 class SkCanvas;
 class SkPaint;
-class SkPath;
 struct SkRect;
 
 namespace android {
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index ceec4fc..3d8a749 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -783,6 +783,7 @@
     Rect bounds(path.getBounds());
     paintInfo.expandBoundsForStroke(&bounds);
     vertexBuffer.setBounds(bounds);
+    vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
 }
 
 template <class TYPE>
@@ -840,6 +841,7 @@
     // expand bounds from vertex coords to pixel data
     paintInfo.expandBoundsForStroke(&bounds);
     vertexBuffer.setBounds(bounds);
+    vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
 }
 
 void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
@@ -890,6 +892,7 @@
     // expand bounds from vertex coords to pixel data
     paintInfo.expandBoundsForStroke(&bounds);
     vertexBuffer.setBounds(bounds);
+    vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index efa271e..9665a68 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -16,13 +16,14 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <utils/Log.h>
+#include "PixelBuffer.h"
 
-#include "Caches.h"
 #include "Debug.h"
 #include "Extensions.h"
-#include "PixelBuffer.h"
 #include "Properties.h"
+#include "renderstate/RenderState.h"
+
+#include <utils/Log.h>
 
 namespace android {
 namespace uirenderer {
@@ -93,14 +94,16 @@
     Caches& mCaches;
 };
 
-GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
+GpuPixelBuffer::GpuPixelBuffer(GLenum format,
+        uint32_t width, uint32_t height)
         : PixelBuffer(format, width, height)
         , mMappedPointer(nullptr)
-        , mCaches(Caches::getInstance()) {
+        , mCaches(Caches::getInstance()){
     glGenBuffers(1, &mBuffer);
-    mCaches.bindPixelBuffer(mBuffer);
+
+    mCaches.pixelBufferState().bind(mBuffer);
     glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW);
-    mCaches.unbindPixelBuffer();
+    mCaches.pixelBufferState().unbind();
 }
 
 GpuPixelBuffer::~GpuPixelBuffer() {
@@ -109,7 +112,7 @@
 
 uint8_t* GpuPixelBuffer::map(AccessMode mode) {
     if (mAccessMode == kAccessMode_None) {
-        mCaches.bindPixelBuffer(mBuffer);
+        mCaches.pixelBufferState().bind(mBuffer);
         mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
 #if DEBUG_OPENGL
         if (!mMappedPointer) {
@@ -128,7 +131,7 @@
 void GpuPixelBuffer::unmap() {
     if (mAccessMode != kAccessMode_None) {
         if (mMappedPointer) {
-            mCaches.bindPixelBuffer(mBuffer);
+            mCaches.pixelBufferState().bind(mBuffer);
             GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
             if (status == GL_FALSE) {
                 ALOGE("Corrupted GPU pixel buffer");
@@ -145,7 +148,7 @@
 
 void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
     // If the buffer is not mapped, unmap() will not bind it
-    mCaches.bindPixelBuffer(mBuffer);
+    mCaches.pixelBufferState().bind(mBuffer);
     unmap();
     glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
             GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
@@ -155,7 +158,8 @@
 // Factory
 ///////////////////////////////////////////////////////////////////////////////
 
-PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
+PixelBuffer* PixelBuffer::create(GLenum format,
+        uint32_t width, uint32_t height, BufferType type) {
     if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
         return new GpuPixelBuffer(format, width, height);
     }
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 04225a2..aac5ec4 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -18,6 +18,7 @@
 #define ANDROID_HWUI_PIXEL_BUFFER_H
 
 #include <GLES3/gl3.h>
+#include <cutils/log.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index fb07dfa..32713e9 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -46,7 +46,7 @@
             glAttachShader(mProgramId, mVertexShader);
             glAttachShader(mProgramId, mFragmentShader);
 
-            position = bindAttrib("position", kBindingPosition);
+            bindAttrib("position", kBindingPosition);
             if (description.hasTexture || description.hasExternalTexture) {
                 texCoords = bindAttrib("texCoords", kBindingTexCoords);
             } else {
@@ -177,12 +177,12 @@
     glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
 }
 
-void Program::setColor(const float r, const float g, const float b, const float a) {
+void Program::setColor(FloatColor color) {
     if (!mHasColorUniform) {
         mColorUniform = getUniform("color");
         mHasColorUniform = true;
     }
-    glUniform4f(mColorUniform, r, g, b, a);
+    glUniform4f(mColorUniform, color.r, color.g, color.b, color.a);
 }
 
 void Program::use() {
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index d05b331..af1e4a7 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -25,6 +25,7 @@
 #include <SkXfermode.h>
 
 #include "Debug.h"
+#include "FloatColor.h"
 #include "Matrix.h"
 #include "Properties.h"
 
@@ -102,7 +103,7 @@
  * A ProgramDescription must be used in conjunction with a ProgramCache.
  */
 struct ProgramDescription {
-    enum ColorModifier {
+    enum ColorFilterMode {
         kColorNone = 0,
         kColorMatrix,
         kColorBlend
@@ -148,7 +149,7 @@
     GLenum bitmapWrapT;
 
     // Color operations
-    ColorModifier colorOp;
+    ColorFilterMode colorOp;
     SkXfermode::Mode colorMode;
 
     // Framebuffer blending (requires Extensions.hasFramebufferFetch())
@@ -363,15 +364,10 @@
     /**
      * Sets the color associated with this shader.
      */
-    void setColor(const float r, const float g, const float b, const float a);
+    void setColor(FloatColor color);
 
     /**
-     * Name of the position attribute.
-     */
-    int position;
-
-    /**
-     * Name of the texCoords attribute if it exists, -1 otherwise.
+     * Name of the texCoords attribute if it exists (kBindingTexCoords), -1 otherwise.
      */
     int texCoords;
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 3bbd520..8c6a91cc 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -404,7 +404,8 @@
 // Constructors/destructors
 ///////////////////////////////////////////////////////////////////////////////
 
-ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
+ProgramCache::ProgramCache(Extensions& extensions)
+        : mHasES3(extensions.getMajorGlVersion() >= 3) {
 }
 
 ProgramCache::~ProgramCache() {
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 30fa0df..1dadda1 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -40,7 +40,7 @@
  */
 class ProgramCache {
 public:
-    ProgramCache();
+    ProgramCache(Extensions& extensions);
     ~ProgramCache();
 
     Program* get(const ProgramDescription& description);
diff --git a/libs/hwui/Query.h b/libs/hwui/Query.h
deleted file mode 100644
index e25b16b..0000000
--- a/libs/hwui/Query.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_QUERY_H
-#define ANDROID_HWUI_QUERY_H
-
-#include <GLES3/gl3.h>
-
-#include "Extensions.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * A Query instance can be used to perform occlusion queries. If the device
- * does not support occlusion queries, the result of a query will always be
- * 0 and the result will always be marked available.
- *
- * To run an occlusion query successfully, you must start end end the query:
- *
- * Query query;
- * query.begin();
- * // execute OpenGL calls
- * query.end();
- * GLuint result = query.getResult();
- */
-class Query {
-public:
-    /**
-     * Possible query targets.
-     */
-    enum Target {
-        /**
-         * Indicates if any sample passed the depth & stencil tests.
-         */
-        kTargetSamples = GL_ANY_SAMPLES_PASSED,
-        /**
-         * Indicates if any sample passed the depth & stencil tests.
-         * The implementation may choose to use a less precise version
-         * of the test, potentially resulting in false positives.
-         */
-        kTargetConservativeSamples = GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
-    };
-
-    /**
-     * Creates a new query with the specified target. The default
-     * target is kTargetSamples (of GL_ANY_SAMPLES_PASSED in OpenGL.)
-     */
-    Query(Target target = kTargetSamples): mActive(false), mTarget(target),
-            mCanQuery(Extensions::getInstance().hasOcclusionQueries()),
-            mQuery(0) {
-    }
-
-    ~Query() {
-        if (mQuery) {
-            glDeleteQueries(1, &mQuery);
-        }
-    }
-
-    /**
-     * Begins the query. If the query has already begun or if the device
-     * does not support occlusion queries, calling this method as no effect.
-     * After calling this method successfully, the query is marked active.
-     */
-    void begin() {
-        if (!mActive && mCanQuery) {
-            if (!mQuery) {
-                glGenQueries(1, &mQuery);
-            }
-
-            glBeginQuery(mTarget, mQuery);
-            mActive = true;
-        }
-    }
-
-    /**
-     * Ends the query. If the query has already begun or if the device
-     * does not support occlusion queries, calling this method as no effect.
-     * After calling this method successfully, the query is marked inactive.
-     */
-    void end() {
-        if (mQuery && mActive) {
-            glEndQuery(mTarget);
-            mActive = false;
-        }
-    }
-
-    /**
-     * Returns true if the query is active, false otherwise.
-     */
-    bool isActive() {
-        return mActive;
-    }
-
-    /**
-     * Returns true if the result of the query is available,
-     * false otherwise. Calling getResult() before the result
-     * is available may result in the calling thread being blocked.
-     * If the device does not support queries, this method always
-     * returns true.
-     */
-    bool isResultAvailable() {
-        if (!mQuery) return true;
-
-        GLuint result;
-        glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &result);
-        return result == GL_TRUE;
-    }
-
-    /**
-     * Returns the result of the query. If the device does not
-     * support queries this method will return 0.
-     *
-     * Calling this method implicitely calls end() if the query
-     * is currently active.
-     */
-    GLuint getResult() {
-        if (!mQuery) return 0;
-
-        end();
-
-        GLuint result;
-        glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT, &result);
-        return result;
-    }
-
-
-private:
-    bool mActive;
-    GLenum mTarget;
-    bool mCanQuery;
-    GLuint mQuery;
-
-}; // class Query
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_QUERY_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index a0a5a1c..659ef6c 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -836,7 +836,6 @@
  */
 template <class T>
 void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
-    const int level = handler.level();
     if (mDisplayListData->isEmpty()) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
         return;
@@ -860,7 +859,7 @@
 #if DEBUG_DISPLAY_LIST
     const Rect& clipRect = renderer.getLocalClipBounds();
     DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
-            level * 2, "", this, getName(),
+            handler.level() * 2, "", this, getName(),
             clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
 #endif
 
@@ -900,7 +899,7 @@
                 for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
                     DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
 #if DEBUG_DISPLAY_LIST
-                    op->output(level + 1);
+                    op->output(handler.level() + 1);
 #endif
                     handler(op, saveCountOffset, properties().getClipToBounds());
 
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index c6483ac..4333792 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -81,7 +81,7 @@
     uint32_t mPixelRefStableID;
 
     friend class ResourceCache;
-    friend class android::key_value_pair_t<BitmapKey, SkBitmap*>;
+    friend struct android::key_value_pair_t<BitmapKey, SkBitmap*>;
 };
 
 class ANDROID_API ResourceCache: public Singleton<ResourceCache> {
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index f8917e3..ca7f48d 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -113,33 +113,6 @@
 #endif
 }
 
-void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
-    int currentIndex = 0;
-    const int rays = SHADOW_RAY_COUNT;
-    // For the penumbra area.
-    for (int layer = 0; layer < 2; layer ++) {
-        int baseIndex = layer * rays;
-        for (int i = 0; i < rays; i++) {
-            shadowIndices[currentIndex++] = i + baseIndex;
-            shadowIndices[currentIndex++] = rays + i + baseIndex;
-        }
-        // To close the loop, back to the ray 0.
-        shadowIndices[currentIndex++] = 0 + baseIndex;
-         // Note this is the same as the first index of next layer loop.
-        shadowIndices[currentIndex++] = rays + baseIndex;
-    }
-
-#if DEBUG_SHADOW
-    if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
-        ALOGW("vertex index count is wrong. current %d, expected %d",
-                currentIndex, MAX_SHADOW_INDEX_COUNT);
-    }
-    for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
-        ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
-    }
-#endif
-}
-
 /**
  * Calculate the centroid of a 2d polygon.
  *
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 16ad91d..c04d8ef 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -78,8 +78,6 @@
             const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
             const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
 
-    static void generateShadowIndices(uint16_t*  shadowIndices);
-
     static Vector2 centroid2d(const Vector2* poly, int polyLength);
 
     static bool isClockwise(const Vector2* polygon, int len);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7fdbf9a..efbb709 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -46,82 +46,87 @@
         canvas->ref();
     }
 
-    virtual SkCanvas* getSkCanvas() {
+    virtual SkCanvas* asSkCanvas() override {
         return mCanvas.get();
     }
 
-    virtual void setBitmap(SkBitmap* bitmap, bool copyState);
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) override;
 
-    virtual bool isOpaque();
-    virtual int width();
-    virtual int height();
+    virtual bool isOpaque() override;
+    virtual int width() override;
+    virtual int height() override;
 
-    virtual int getSaveCount() const;
-    virtual int save(SkCanvas::SaveFlags flags);
-    virtual void restore();
-    virtual void restoreToCount(int saveCount);
+    virtual int getSaveCount() const override;
+    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual void restore() override;
+    virtual void restoreToCount(int saveCount) override;
 
     virtual int saveLayer(float left, float top, float right, float bottom,
-                const SkPaint* paint, SkCanvas::SaveFlags flags);
+                const SkPaint* paint, SkCanvas::SaveFlags flags) override;
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags);
+            int alpha, SkCanvas::SaveFlags flags) override;
 
-    virtual void getMatrix(SkMatrix* outMatrix) const;
-    virtual void setMatrix(const SkMatrix& matrix);
-    virtual void concat(const SkMatrix& matrix);
-    virtual void rotate(float degrees);
-    virtual void scale(float sx, float sy);
-    virtual void skew(float sx, float sy);
-    virtual void translate(float dx, float dy);
+    virtual void getMatrix(SkMatrix* outMatrix) const override;
+    virtual void setMatrix(const SkMatrix& matrix) override;
+    virtual void concat(const SkMatrix& matrix) override;
+    virtual void rotate(float degrees) override;
+    virtual void scale(float sx, float sy) override;
+    virtual void skew(float sx, float sy) override;
+    virtual void translate(float dx, float dy) override;
 
-    virtual bool getClipBounds(SkRect* outRect) const;
-    virtual bool quickRejectRect(float left, float top, float right, float bottom) const;
-    virtual bool quickRejectPath(const SkPath& path) const;
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op);
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
+    virtual bool getClipBounds(SkRect* outRect) const override;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
+    virtual bool quickRejectPath(const SkPath& path) const override;
+    virtual bool clipRect(float left, float top, float right, float bottom,
+            SkRegion::Op op) override;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) override;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override;
 
-    virtual SkDrawFilter* getDrawFilter();
-    virtual void setDrawFilter(SkDrawFilter* drawFilter);
+    virtual SkDrawFilter* getDrawFilter() override;
+    virtual void setDrawFilter(SkDrawFilter* drawFilter) override;
 
-    virtual void drawColor(int color, SkXfermode::Mode mode);
-    virtual void drawPaint(const SkPaint& paint);
+    virtual void drawColor(int color, SkXfermode::Mode mode) override;
+    virtual void drawPaint(const SkPaint& paint) override;
 
-    virtual void drawPoint(float x, float y, const SkPaint& paint);
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint);
+    virtual void drawPoint(float x, float y, const SkPaint& paint) override;
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
     virtual void drawLine(float startX, float startY, float stopX, float stopY,
-            const SkPaint& paint);
-    virtual void drawLines(const float* points, int count, const SkPaint& paint);
-    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint);
+            const SkPaint& paint) override;
+    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawRect(float left, float top, float right, float bottom,
+            const SkPaint& paint) override;
     virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint& paint);
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint);
-    virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint);
+            float rx, float ry, const SkPaint& paint) override;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+    virtual void drawOval(float left, float top, float right, float bottom,
+            const SkPaint& paint) override;
     virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint);
-    virtual void drawPath(const SkPath& path, const SkPaint& paint);
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
     virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
             const float* verts, const float* tex, const int* colors,
-            const uint16_t* indices, int indexCount, const SkPaint& paint);
+            const uint16_t* indices, int indexCount, const SkPaint& paint) override;
 
-    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint);
-    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint);
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
+            const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+            const SkPaint* paint) override;
     virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
+            float dstRight, float dstBottom, const SkPaint* paint) override;
     virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint);
+            const float* vertices, const int* colors, const SkPaint* paint) override;
 
     virtual void drawText(const uint16_t* text, const float* positions, int count,
             const SkPaint& paint, float x, float y,
             float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
-            float totalAdvance);
+            float totalAdvance) override;
     virtual void drawPosText(const uint16_t* text, const float* positions, int count,
-            int posCount, const SkPaint& paint);
+            int posCount, const SkPaint& paint) override;
     virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const SkPaint& paint);
+            float hOffset, float vOffset, const SkPaint& paint) override;
 
-    virtual bool drawTextAbsolutePos() const { return true; }
+    virtual bool drawTextAbsolutePos() const  override { return true; }
 
 private:
     struct SaveRec {
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
new file mode 100644
index 0000000..de5f91c
--- /dev/null
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -0,0 +1,347 @@
+/*
+ * 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 "SkiaCanvasProxy.h"
+
+#include <cutils/log.h>
+#include <SkPatchUtils.h>
+
+namespace android {
+namespace uirenderer {
+
+SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas)
+        : INHERITED(canvas->width(), canvas->height())
+        , mCanvas(canvas) {}
+
+void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
+    mCanvas->drawPaint(paint);
+}
+
+void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
+        const SkPaint& paint) {
+    // convert the SkPoints into floats
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    const size_t floatCount = count << 1;
+    const float* floatArray = &pts[0].fX;
+
+    switch (pointMode) {
+        case kPoints_PointMode: {
+            mCanvas->drawPoints(floatArray, floatCount, paint);
+            break;
+        }
+        case kLines_PointMode: {
+            mCanvas->drawLines(floatArray, floatCount, paint);
+            break;
+        }
+        case kPolygon_PointMode: {
+            SkPaint strokedPaint(paint);
+            strokedPaint.setStyle(SkPaint::kStroke_Style);
+
+            SkPath path;
+            for (size_t i = 0; i < count - 1; i++) {
+                path.moveTo(pts[i]);
+                path.lineTo(pts[i+1]);
+                this->drawPath(path, strokedPaint);
+                path.rewind();
+            }
+            break;
+        }
+        default:
+            LOG_ALWAYS_FATAL("Unknown point type");
+    }
+}
+
+void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
+    mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
+    mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
+    if (!roundRect.isComplex()) {
+        const SkRect& rect = roundRect.rect();
+        SkVector radii = roundRect.getSimpleRadii();
+        mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+                               radii.fX, radii.fY, paint);
+    } else {
+        SkPath path;
+        path.addRRect(roundRect);
+        mCanvas->drawPath(path, paint);
+    }
+}
+
+void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
+    mCanvas->drawPath(path, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
+        const SkPaint* paint) {
+    mCanvas->drawBitmap(bitmap, left, top, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* srcPtr,
+        const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags) {
+    SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(bitmap.width(), bitmap.height());
+    mCanvas->drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+                        dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+        const SkRect& dst, const SkPaint*) {
+    //TODO make nine-patch drawing a method on Canvas.h
+    SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
+}
+
+void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top,
+        const SkPaint* paint) {
+    mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+    mCanvas->setMatrix(SkMatrix::I());
+    mCanvas->drawBitmap(bitmap, left, top, paint);
+    mCanvas->restore();
+}
+
+void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
+        const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
+        int indexCount, const SkPaint& paint) {
+    // convert the SkPoints into floats
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    const int floatCount = vertexCount << 1;
+    const float* vArray = &vertices[0].fX;
+    const float* tArray = (texs) ? &texs[0].fX : NULL;
+    const int* cArray = (colors) ? (int*)colors : NULL;
+    mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
+}
+
+SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
+    SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
+    return NULL;
+}
+
+void SkiaCanvasProxy::willSave() {
+    mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+}
+
+SkCanvas::SaveLayerStrategy SkiaCanvasProxy::willSaveLayer(const SkRect* rectPtr,
+        const SkPaint* paint, SaveFlags flags) {
+    SkRect rect;
+    if (rectPtr) {
+        rect = *rectPtr;
+    } else if(!mCanvas->getClipBounds(&rect)) {
+        rect = SkRect::MakeEmpty();
+    }
+    mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint, flags);
+    return SkCanvas::kNoLayer_SaveLayerStrategy;
+}
+
+void SkiaCanvasProxy::willRestore() {
+    mCanvas->restore();
+}
+
+void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
+    mCanvas->concat(matrix);
+}
+
+void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
+    mCanvas->setMatrix(matrix);
+}
+
+void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
+        const SkPaint& paint) {
+    SkPath path;
+    path.addRRect(outer);
+    path.addRRect(inner);
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    this->drawPath(path, paint);
+}
+
+/**
+ * Utility class that converts the incoming text & paint from the given encoding
+ * into glyphIDs.
+ */
+class GlyphIDConverter {
+public:
+    GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
+        paint = origPaint;
+        if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
+            glyphIDs = (uint16_t*)text;
+            count = byteLength >> 1;
+        } else {
+            storage.reset(byteLength); // ensures space for one glyph per ID given UTF8 encoding.
+            glyphIDs = storage.get();
+            count = paint.textToGlyphs(text, byteLength, storage.get());
+            paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        }
+    }
+
+    SkPaint paint;
+    uint16_t* glyphIDs;
+    int count;
+private:
+    SkAutoSTMalloc<32, uint16_t> storage;
+};
+
+void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+        const SkPaint& origPaint) {
+    // convert to glyphIDs if necessary
+    GlyphIDConverter glyphs(text, byteLength, origPaint);
+
+    // compute the glyph positions
+    SkAutoSTMalloc<32, SkPoint> pointStorage(glyphs.count);
+    SkAutoSTMalloc<32, SkScalar> glyphWidths(glyphs.count);
+    glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
+
+    // compute conservative bounds
+    // NOTE: We could call the faster paint.getFontBounds for a less accurate,
+    //       but even more conservative bounds if this  is too slow.
+    SkRect bounds;
+    glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
+
+    // adjust for non-left alignment
+    if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
+        SkScalar stop = 0;
+        for (int i = 0; i < glyphs.count; i++) {
+            stop += glyphWidths[i];
+        }
+        if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
+            stop = SkScalarHalf(stop);
+        }
+        if (glyphs.paint.isVerticalText()) {
+            y -= stop;
+        } else {
+            x -= stop;
+        }
+    }
+
+    // setup the first glyph position and adjust bounds if needed
+    if (mCanvas->drawTextAbsolutePos()) {
+        bounds.offset(x,y);
+        pointStorage[0].set(x, y);
+    } else {
+        pointStorage[0].set(0, 0);
+    }
+
+    // setup the remaining glyph positions
+    if (glyphs.paint.isVerticalText()) {
+        for (int i = 1; i < glyphs.count; i++) {
+            pointStorage[i].set(x, glyphWidths[i-1] + pointStorage[i-1].fY);
+        }
+    } else {
+        for (int i = 1; i < glyphs.count; i++) {
+            pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, y);
+        }
+    }
+
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    mCanvas->drawText(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
+                      x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
+}
+
+void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+        const SkPaint& origPaint) {
+    // convert to glyphIDs if necessary
+    GlyphIDConverter glyphs(text, byteLength, origPaint);
+
+    // convert to relative positions if necessary
+    int x, y;
+    const SkPoint* posArray;
+    SkAutoSTMalloc<32, SkPoint> pointStorage;
+    if (mCanvas->drawTextAbsolutePos()) {
+        x = 0;
+        y = 0;
+        posArray = pos;
+    } else {
+        x = pos[0].fX;
+        y = pos[0].fY;
+        posArray = pointStorage.reset(glyphs.count);
+        for (int i = 0; i < glyphs.count; i++) {
+            pointStorage[i].fX = pos[i].fX- x;
+            pointStorage[i].fY = pos[i].fY- y;
+        }
+    }
+
+    // compute conservative bounds
+    // NOTE: We could call the faster paint.getFontBounds for a less accurate,
+    //       but even more conservative bounds if this  is too slow.
+    SkRect bounds;
+    glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
+
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    mCanvas->drawText(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
+                      bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
+}
+
+void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+        SkScalar constY, const SkPaint& paint) {
+    const size_t pointCount = byteLength >> 1;
+    SkAutoSTMalloc<32, SkPoint> storage(pointCount);
+    SkPoint* pts = storage.get();
+    for (size_t i = 0; i < pointCount; i++) {
+        pts[i].set(xpos[i], constY);
+    }
+    this->onDrawPosText(text, byteLength, pts, paint);
+}
+
+void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+        const SkMatrix* matrix, const SkPaint& origPaint) {
+    // convert to glyphIDs if necessary
+    GlyphIDConverter glyphs(text, byteLength, origPaint);
+    mCanvas->drawTextOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
+}
+
+void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+        const SkPaint& paint) {
+    SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported");
+}
+
+void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+        const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+    SkPatchUtils::VertexData data;
+
+    SkMatrix matrix;
+    mCanvas->getMatrix(&matrix);
+    SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
+
+    // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
+    // If it fails to generate the vertices, then we do not draw.
+    if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) {
+        this->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
+                           data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
+                           paint);
+    }
+}
+
+void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) {
+    mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
+}
+
+void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkRegion::Op op, ClipEdgeStyle) {
+    SkPath path;
+    path.addRRect(roundRect);
+    mCanvas->clipPath(&path, op);
+}
+
+void SkiaCanvasProxy::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) {
+    mCanvas->clipPath(&path, op);
+}
+
+void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkRegion::Op op) {
+    mCanvas->clipRegion(&region, op);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
new file mode 100644
index 0000000..4322fcf
--- /dev/null
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkiaCanvasProxy_DEFINED
+#define SkiaCanvasProxy_DEFINED
+
+#include <cutils/compiler.h>
+#include <SkCanvas.h>
+
+#include "Canvas.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * This class serves as a proxy between Skia's SkCanvas and Android Framework's
+ * Canvas.  The class does not maintain any state and will pass through any request
+ * directly to the Canvas provided in the constructor.
+ *
+ * Upon construction it is expected that the provided Canvas has already been
+ * prepared for recording and will continue to be in the recording state while
+ * this proxy class is being used.
+ */
+class ANDROID_API SkiaCanvasProxy : public SkCanvas {
+public:
+    SkiaCanvasProxy(Canvas* canvas);
+    virtual ~SkiaCanvasProxy() {}
+
+protected:
+
+    virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
+
+    virtual void willSave() override;
+    virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override;
+    virtual void willRestore() override;
+
+    virtual void didConcat(const SkMatrix&) override;
+    virtual void didSetMatrix(const SkMatrix&) override;
+
+    virtual void onDrawPaint(const SkPaint& paint) override;
+    virtual void onDrawPoints(PointMode, size_t count, const SkPoint pts[],
+                              const SkPaint&) override;
+    virtual void onDrawOval(const SkRect&, const SkPaint&) override;
+    virtual void onDrawRect(const SkRect&, const SkPaint&) override;
+    virtual void onDrawRRect(const SkRRect&, const SkPaint&) override;
+    virtual void onDrawPath(const SkPath& path, const SkPaint&) override;
+    virtual void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
+                              const SkPaint*) override;
+    virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
+                                  const SkPaint* paint, DrawBitmapRectFlags flags) override;
+    virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+                                  const SkRect& dst, const SkPaint*) override;
+    virtual void onDrawSprite(const SkBitmap&, int left, int top,
+                              const SkPaint*) override;
+    virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
+                                const SkPoint texs[], const SkColor colors[], SkXfermode*,
+                                const uint16_t indices[], int indexCount,
+                                const SkPaint&) override;
+
+    virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+
+    virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+                            const SkPaint&) override;
+    virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+                               const SkPaint&) override;
+    virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+                                SkScalar constY, const SkPaint&) override;
+    virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+                                  const SkMatrix* matrix, const SkPaint&) override;
+    virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                                const SkPaint& paint) override;
+
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) override;
+
+    virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
+    virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
+    virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
+    virtual void onClipRegion(const SkRegion&, SkRegion::Op) override;
+
+private:
+    Canvas* mCanvas;
+
+    typedef SkCanvas INHERITED;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // SkiaCanvasProxy_DEFINED
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 2c09344..9c929da 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -57,7 +57,7 @@
 }
 
 static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
-    caches->bindTexture(texture->id);
+    caches->textureState().bindTexture(texture->id);
     texture->setWrapST(wrapS, wrapT);
 }
 
@@ -176,7 +176,7 @@
     }
 
     GLuint textureSlot = (*textureUnit)++;
-    caches->activeTexture(textureSlot);
+    caches->textureState().activateTexture(textureSlot);
 
     const float width = layer->getWidth();
     const float height = layer->getHeight();
@@ -191,11 +191,11 @@
     layer->setWrap(GL_CLAMP_TO_EDGE);
     layer->setFilter(GL_LINEAR);
 
-    Program* program = caches->currentProgram;
-    glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
-    glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+    Program& program = caches->program();
+    glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
+    glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
+    glUniform2f(program.getUniform("textureDimension"), 1.0f / width, 1.0f / height);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -270,14 +270,14 @@
     }
 
     GLuint textureSlot = (*textureUnit)++;
-    Caches::getInstance().activeTexture(textureSlot);
+    Caches::getInstance().textureState().activateTexture(textureSlot);
 
     BitmapShaderInfo shaderInfo;
     if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) {
         return;
     }
 
-    Program* program = caches->currentProgram;
+    Program& program = caches->program();
     Texture* texture = shaderInfo.texture;
 
     const AutoTexture autoCleanup(texture);
@@ -290,10 +290,10 @@
     bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
     texture->setFilter(GL_LINEAR);
 
-    glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
-    glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+    glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
+    glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width,
+    glUniform2f(program.getUniform("textureDimension"), 1.0f / shaderInfo.width,
             1.0f / shaderInfo.height);
 }
 
@@ -381,7 +381,7 @@
 
     SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
 
-    Program* program = caches->currentProgram;
+    Program& program = caches->program();
     if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
         if (gradInfo.fColorCount > COLOR_COUNT) {
             // There was not enough room in our arrays for all the colors and offsets. Try again,
@@ -392,7 +392,7 @@
             shader.asAGradient(&gradInfo);
         }
         GLuint textureSlot = (*textureUnit)++;
-        caches->activeTexture(textureSlot);
+        caches->textureState().activateTexture(textureSlot);
 
 #ifndef SK_SCALAR_IS_FLOAT
     #error Need to convert gradInfo.fColorOffsets to float!
@@ -402,10 +402,10 @@
 
         // Uniforms
         bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
-        glUniform1i(program->getUniform("gradientSampler"), textureSlot);
+        glUniform1i(program.getUniform("gradientSampler"), textureSlot);
     } else {
-        bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]);
-        bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]);
+        bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]);
+        bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]);
     }
 
     caches->dither.setupProgram(program, textureUnit);
@@ -428,7 +428,7 @@
 
     mat4 screenSpace;
     computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
-    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
+    glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 49fb4ba..597d95c 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -203,8 +203,8 @@
     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
             this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
     const Rect& clipRect(mClipArea->getClipRect());
-    ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
-            clipRect, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+    ALOGD("  ClipRect %.1f %.1f %.1f %.1f",
+            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
     ALOGD("  Transform (at %p):", transform);
     transform->dump();
 }
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index a03192a..b3b06d6 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -1031,7 +1031,7 @@
     ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Spot Vertex Buffer");
     ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Spot Index Buffer");
 
-    shadowTriangleStrip.setMode(VertexBuffer::kIndices);
+    shadowTriangleStrip.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
     shadowTriangleStrip.computeBounds<AlphaVertex>();
 }
 
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 4f028d5..66de333 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -385,7 +385,9 @@
     if (mShadowProcessor == nullptr) {
         mShadowProcessor = new ShadowProcessor(Caches::getInstance());
     }
-    mShadowProcessor->add(task);
+    if (!mShadowProcessor->add(task)) {
+        mShadowProcessor->process(task);
+    }
 
     task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
     mShadowCache.put(key, task.get());
@@ -421,7 +423,9 @@
         if (mProcessor == nullptr) {
             mProcessor = new TessellationProcessor(Caches::getInstance());
         }
-        mProcessor->add(task);
+        if (!mProcessor->add(task)) {
+            mProcessor->process(task);
+        }
         mCache.put(entry, buffer);
     }
     return buffer;
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 4ec298d..c2e88f3 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -207,7 +207,7 @@
 
         glGenTextures(1, &texture->id);
 
-        caches.bindTexture(texture->id);
+        caches.textureState().bindTexture(texture->id);
         // Textures are Alpha8
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 58fd972..512f5cf 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -24,18 +24,44 @@
 namespace android {
 namespace uirenderer {
 
-Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
-        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(nullptr), isInUse(false),
-        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
-        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
-        mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
+Texture::Texture()
+        : id(0)
+        , generation(0)
+        , blend(false)
+        , width(0)
+        , height(0)
+        , cleanup(false)
+        , bitmapSize(0)
+        , mipMap(false)
+        , uvMapper(nullptr)
+        , isInUse(false)
+        , mWrapS(GL_CLAMP_TO_EDGE)
+        , mWrapT(GL_CLAMP_TO_EDGE)
+        , mMinFilter(GL_NEAREST)
+        , mMagFilter(GL_NEAREST)
+        , mFirstFilter(true)
+        , mFirstWrap(true)
+        , mCaches(Caches::getInstance()) {
 }
 
-Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
-        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(nullptr), isInUse(false),
-        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
-        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
-        mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
+Texture::Texture(Caches& caches)
+        : id(0)
+        , generation(0)
+        , blend(false)
+        , width(0)
+        , height(0)
+        , cleanup(false)
+        , bitmapSize(0)
+        , mipMap(false)
+        , uvMapper(nullptr)
+        , isInUse(false)
+        , mWrapS(GL_CLAMP_TO_EDGE)
+        , mWrapT(GL_CLAMP_TO_EDGE)
+        , mMinFilter(GL_NEAREST)
+        , mMagFilter(GL_NEAREST)
+        , mFirstFilter(true)
+        , mFirstWrap(true)
+        , mCaches(caches) {
 }
 
 void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
@@ -48,7 +74,7 @@
         mWrapT = wrapT;
 
         if (bindTexture) {
-            mCaches.bindTexture(renderTarget, id);
+            mCaches.textureState().bindTexture(renderTarget, id);
         }
 
         glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
@@ -66,7 +92,7 @@
         mMagFilter = mag;
 
         if (bindTexture) {
-            mCaches.bindTexture(renderTarget, id);
+            mCaches.textureState().bindTexture(renderTarget, id);
         }
 
         if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
@@ -77,7 +103,7 @@
 }
 
 void Texture::deleteTexture() const {
-    mCaches.deleteTexture(id);
+    mCaches.textureState().deleteTexture(id);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 524f206..f4f8e44 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -38,10 +38,12 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-TextureCache::TextureCache():
-        mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
-        mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE), mAssetAtlas(nullptr) {
+TextureCache::TextureCache()
+        : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
+        , mSize(0)
+        , mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE))
+        , mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE)
+        , mAssetAtlas(nullptr) {
     char property[PROPERTY_VALUE_MAX];
     if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting texture cache size to %sMB", property);
@@ -59,20 +61,6 @@
                 DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f);
     }
 
-    init();
-}
-
-TextureCache::TextureCache(uint32_t maxByteSize):
-        mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(maxByteSize), mAssetAtlas(nullptr) {
-    init();
-}
-
-TextureCache::~TextureCache() {
-    mCache.clear();
-}
-
-void TextureCache::init() {
     mCache.setOnEntryRemovedListener(this);
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
@@ -81,6 +69,10 @@
     mDebugEnabled = readDebugLevel() & kDebugCaches;
 }
 
+TextureCache::~TextureCache() {
+    mCache.clear();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Size management
 ///////////////////////////////////////////////////////////////////////////////
@@ -280,7 +272,7 @@
 
     // We could also enable mipmapping if both bitmap dimensions are powers
     // of 2 but we'd have to deal with size changes. Let's keep this simple
-    const bool canMipMap = Extensions::getInstance().hasNPot();
+    const bool canMipMap = Caches::getInstance().extensions().hasNPot();
 
     // If the texture had mipmap enabled but not anymore,
     // force a glTexImage2D to discard the mipmap levels
@@ -296,7 +288,7 @@
     texture->width = bitmap->width();
     texture->height = bitmap->height();
 
-    Caches::getInstance().bindTexture(texture->id);
+    Caches::getInstance().textureState().bindTexture(texture->id);
 
     switch (bitmap->colorType()) {
     case kAlpha_8_SkColorType:
@@ -355,7 +347,8 @@
 void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
         GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
     glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
-    const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
+    const bool useStride = stride != width
+            && Caches::getInstance().extensions().hasUnpackRowLength();
     if ((stride == width) || useStride) {
         if (useStride) {
             glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index b97d92d..a2c6380 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -52,10 +52,9 @@
  * Any texture added to the cache causing the cache to grow beyond the maximum
  * allowed size will also cause the oldest texture to be kicked out.
  */
-class TextureCache: public OnEntryRemoved<uint32_t, Texture*> {
+class TextureCache : public OnEntryRemoved<uint32_t, Texture*> {
 public:
     TextureCache();
-    TextureCache(uint32_t maxByteSize);
     ~TextureCache();
 
     /**
@@ -146,8 +145,6 @@
     void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
             GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
 
-    void init();
-
     LruCache<uint32_t, Texture*> mCache;
 
     uint32_t mSize;
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index aa6acc9..7c3f2fd 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_HWUI_VECTOR_H
 #define ANDROID_HWUI_VECTOR_H
 
+#include <math.h>
+#include <utils/Log.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 5b80bbd..fd3845d 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,11 +19,9 @@
 
 #include "Vector.h"
 
-#include <type_traits>
+#include "utils/Macros.h"
 
-#define REQUIRE_COMPATIBLE_LAYOUT(TARGET_TYPE) \
-        static_assert(std::is_standard_layout<TARGET_TYPE>::value, \
-        #TARGET_TYPE " must have standard layout")
+#include <type_traits>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index d81dd42..9be4d84 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -24,11 +24,10 @@
 
 class VertexBuffer {
 public:
-    enum Mode {
-        kStandard = 0,
-        kOnePolyRingShadow = 1,
-        kTwoPolyRingShadow = 2,
-        kIndices = 3
+    enum MeshFeatureFlags {
+        kNone = 0,
+        kAlpha = 1 << 0,
+        kIndices = 1 << 1,
     };
 
     VertexBuffer()
@@ -39,7 +38,7 @@
             , mAllocatedVertexCount(0)
             , mAllocatedIndexCount(0)
             , mByteCount(0)
-            , mMode(kStandard)
+            , mMeshFeatureFlags(kNone)
             , mReallocBuffer(nullptr)
             , mCleanupMethod(nullptr)
             , mCleanupIndexMethod(nullptr)
@@ -135,10 +134,12 @@
     void updateVertexCount(unsigned int newCount)  {
         mVertexCount = MathUtils::min(newCount, mAllocatedVertexCount);
     }
-    Mode getMode() const { return mMode; }
+    MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
+    void setMeshFeatureFlags(int flags) {
+        mMeshFeatureFlags = static_cast<MeshFeatureFlags>(flags);
+    }
 
     void setBounds(Rect bounds) { mBounds = bounds; }
-    void setMode(Mode mode) { mMode = mode; }
 
     template <class TYPE>
     void createDegenerateSeparators(int allocSize) {
@@ -166,7 +167,7 @@
     unsigned int mAllocatedIndexCount;
     unsigned int mByteCount;
 
-    Mode mMode;
+    MeshFeatureFlags mMeshFeatureFlags;
 
     void* mReallocBuffer; // used for multi-allocation
 
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 128e392..9314126 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -120,7 +120,7 @@
     // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
     // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
     // With OpenGL ES 2.0 we have to upload entire stripes instead.
-    mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
+    mHasUnpackRowLength = mCaches.extensions().hasUnpackRowLength();
 }
 
 CacheTexture::~CacheTexture() {
@@ -157,7 +157,7 @@
         mTexture = nullptr;
     }
     if (mTextureId) {
-        mCaches.deleteTexture(mTextureId);
+        mCaches.textureState().deleteTexture(mTextureId);
         mTextureId = 0;
     }
     mDirty = false;
@@ -169,7 +169,7 @@
        mLinearFiltering = linearFiltering;
 
        const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
-       if (bind) mCaches.bindTexture(getTextureId());
+       if (bind) mCaches.textureState().bindTexture(getTextureId());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    }
@@ -189,7 +189,7 @@
     if (!mTextureId) {
         glGenTextures(1, &mTextureId);
 
-        mCaches.bindTexture(mTextureId);
+        mCaches.textureState().bindTexture(mTextureId);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         // Initialize texture dimensions
         glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
new file mode 100644
index 0000000..789f6cc
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 <renderstate/Blend.h>
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure mapping Skia xfermodes to OpenGL blending factors.
+ */
+struct Blender {
+    SkXfermode::Mode mode;
+    GLenum src;
+    GLenum dst;
+};
+
+// In this array, the index of each Blender equals the value of the first
+// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
+const Blender kBlends[] = {
+    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
+    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
+    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
+    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
+    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
+    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
+    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
+};
+
+// This array contains the swapped version of each SkXfermode. For instance
+// this array's SrcOver blending mode is actually DstOver. You can refer to
+// createLayer() for more information on the purpose of this array.
+const Blender kBlendsSwap[] = {
+    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
+    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
+    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
+    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
+    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
+    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
+    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
+};
+
+Blend::Blend()
+    : mEnabled(false)
+    , mSrcMode(GL_ZERO)
+    , mDstMode(GL_ZERO) {
+    // gl blending off by default
+}
+
+void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) {
+    GLenum srcMode;
+    GLenum dstMode;
+    getFactors(mode, swapSrcDst, &srcMode, &dstMode);
+    setFactors(srcMode, dstMode);
+}
+
+void Blend::disable() {
+    if (mEnabled) {
+        glDisable(GL_BLEND);
+        mEnabled = false;
+    }
+}
+
+void Blend::invalidate() {
+    syncEnabled();
+    mSrcMode = mDstMode = GL_ZERO;
+}
+
+void Blend::syncEnabled() {
+    if (mEnabled) {
+        glEnable(GL_BLEND);
+    } else {
+        glDisable(GL_BLEND);
+    }
+}
+
+void Blend::getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst) {
+    *outSrc = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src;
+    *outDst = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst;
+}
+
+void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
+    if (srcMode == GL_ZERO && dstMode == GL_ZERO) {
+        disable();
+    } else {
+        if (!mEnabled) {
+            glEnable(GL_BLEND);
+            mEnabled = true;
+        }
+
+        if (srcMode != mSrcMode || dstMode != mDstMode) {
+            glBlendFunc(srcMode, dstMode);
+            mSrcMode = srcMode;
+            mDstMode = dstMode;
+        }
+    }
+}
+
+void Blend::dump() {
+    ALOGD("Blend: enabled %d, func src %d, dst %d", mEnabled, mSrcMode, mDstMode);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
new file mode 100644
index 0000000..6d0c115c
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_BLEND_H
+#define RENDERSTATE_BLEND_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Blend {
+    friend class RenderState;
+public:
+    void enable(SkXfermode::Mode mode, bool swapSrcDst);
+    void disable();
+    void syncEnabled();
+
+    static void getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst);
+    void setFactors(GLenum src, GLenum dst);
+
+    void dump();
+private:
+    Blend();
+    void invalidate();
+    bool mEnabled;
+    GLenum mSrcMode;
+    GLenum mDstMode;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
new file mode 100644
index 0000000..585fb86
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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 "renderstate/MeshState.h"
+
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+MeshState::MeshState()
+        : mCurrentIndicesBuffer(0)
+        , mCurrentPixelBuffer(0)
+        , mCurrentPositionPointer(this)
+        , mCurrentPositionStride(0)
+        , mCurrentTexCoordsPointer(this)
+        , mCurrentTexCoordsStride(0)
+        , mTexCoordsArrayEnabled(false)
+        , mQuadListIndices(0) {
+    glGenBuffers(1, &mUnitQuadBuffer);
+    glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
+
+    mCurrentBuffer = mUnitQuadBuffer;
+
+    std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[kMaxNumberOfQuads * 6]);
+    for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
+        uint16_t quad = i * 4;
+        int index = i * 6;
+        regionIndices[index    ] = quad;       // top-left
+        regionIndices[index + 1] = quad + 1;   // top-right
+        regionIndices[index + 2] = quad + 2;   // bottom-left
+        regionIndices[index + 3] = quad + 2;   // bottom-left
+        regionIndices[index + 4] = quad + 1;   // top-right
+        regionIndices[index + 5] = quad + 3;   // bottom-right
+    }
+    glGenBuffers(1, &mQuadListIndices);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, kMaxNumberOfQuads * 6 * sizeof(uint16_t),
+            regionIndices.get(), GL_STATIC_DRAW);
+    mCurrentIndicesBuffer = mQuadListIndices;
+
+    // position attribute always enabled
+    glEnableVertexAttribArray(Program::kBindingPosition);
+}
+
+MeshState::~MeshState() {
+    glDeleteBuffers(1, &mUnitQuadBuffer);
+    mCurrentBuffer = 0;
+
+    glDeleteBuffers(1, &mQuadListIndices);
+    mQuadListIndices = 0;
+}
+
+void MeshState::dump() {
+    ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
+    ALOGD("MeshState vertices: vertex data %p, stride %d",
+            mCurrentPositionPointer, mCurrentPositionStride);
+    ALOGD("MeshState texCoord: data %p, stride %d",
+            mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Buffer Objects
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindMeshBuffer() {
+    return bindMeshBuffer(mUnitQuadBuffer);
+}
+
+bool MeshState::bindMeshBuffer(GLuint buffer) {
+    if (!buffer) buffer = mUnitQuadBuffer;
+    return bindMeshBufferInternal(buffer);
+}
+
+bool MeshState::unbindMeshBuffer() {
+    return bindMeshBufferInternal(0);
+}
+
+bool MeshState::bindMeshBufferInternal(GLuint buffer) {
+    if (mCurrentBuffer != buffer) {
+        glBindBuffer(GL_ARRAY_BUFFER, buffer);
+        mCurrentBuffer = buffer;
+        return true;
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Vertices
+///////////////////////////////////////////////////////////////////////////////
+
+void MeshState::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
+    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
+        glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+        mCurrentPositionPointer = vertices;
+        mCurrentPositionStride = stride;
+    }
+}
+
+void MeshState::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
+    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
+        glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+        mCurrentTexCoordsPointer = vertices;
+        mCurrentTexCoordsStride = stride;
+    }
+}
+
+void MeshState::resetVertexPointers() {
+    mCurrentPositionPointer = this;
+    mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::resetTexCoordsVertexPointer() {
+    mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::enableTexCoordsVertexArray() {
+    if (!mTexCoordsArrayEnabled) {
+        glEnableVertexAttribArray(Program::kBindingTexCoords);
+        mCurrentTexCoordsPointer = this;
+        mTexCoordsArrayEnabled = true;
+    }
+}
+
+void MeshState::disableTexCoordsVertexArray() {
+    if (mTexCoordsArrayEnabled) {
+        glDisableVertexAttribArray(Program::kBindingTexCoords);
+        mTexCoordsArrayEnabled = false;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Indices
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindIndicesBufferInternal(const GLuint buffer) {
+    if (mCurrentIndicesBuffer != buffer) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+        mCurrentIndicesBuffer = buffer;
+        return true;
+    }
+    return false;
+}
+
+bool MeshState::bindQuadIndicesBuffer() {
+    return bindIndicesBufferInternal(mQuadListIndices);
+}
+
+bool MeshState::unbindIndicesBuffer() {
+    if (mCurrentIndicesBuffer) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+        mCurrentIndicesBuffer = 0;
+        return true;
+    }
+    return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
new file mode 100644
index 0000000..3c92ad8
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_MESHSTATE_H
+#define RENDERSTATE_MESHSTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+
+// Maximum number of quads that pre-allocated meshes can draw
+const uint32_t kMaxNumberOfQuads = 2048;
+
+// This array is never used directly but used as a memcpy source in the
+// OpenGLRenderer constructor
+const TextureVertex kUnitQuadVertices[] = {
+        { 0, 0, 0, 0 },
+        { 1, 0, 1, 0 },
+        { 0, 1, 0, 1 },
+        { 1, 1, 1, 1 },
+};
+
+const GLsizei kVertexStride = sizeof(Vertex);
+const GLsizei kAlphaVertexStride = sizeof(AlphaVertex);
+const GLsizei kTextureVertexStride = sizeof(TextureVertex);
+
+const GLsizei kMeshTextureOffset = 2 * sizeof(float);
+const GLsizei kVertexAlphaOffset = 2 * sizeof(float);
+const GLsizei kVertexAAWidthOffset = 2 * sizeof(float);
+const GLsizei kVertexAALengthOffset = 3 * sizeof(float);
+const GLsizei kUnitQuadCount = 4;
+
+class MeshState {
+private:
+    friend class RenderState;
+
+public:
+    ~MeshState();
+    void dump();
+    ///////////////////////////////////////////////////////////////////////////////
+    // Buffer objects
+    ///////////////////////////////////////////////////////////////////////////////
+    /**
+     * Binds the VBO used to render simple textured quads.
+     */
+    bool bindMeshBuffer();
+
+    /**
+     * Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad.
+     */
+    bool bindMeshBuffer(GLuint buffer);
+
+    /**
+     * Unbinds the VBO used to render simple textured quads.
+     */
+    bool unbindMeshBuffer();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Vertices
+    ///////////////////////////////////////////////////////////////////////////////
+    /**
+     * Binds an attrib to the specified float vertex pointer.
+     * Assumes a stride of gTextureVertexStride and a size of 2.
+     */
+    void bindPositionVertexPointer(bool force, const GLvoid* vertices,
+            GLsizei stride = kTextureVertexStride);
+
+    /**
+     * Binds an attrib to the specified float vertex pointer.
+     * Assumes a stride of gTextureVertexStride and a size of 2.
+     */
+    void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices,
+            GLsizei stride = kTextureVertexStride);
+
+    /**
+     * Resets the vertex pointers.
+     */
+    void resetVertexPointers();
+    void resetTexCoordsVertexPointer();
+
+    void enableTexCoordsVertexArray();
+    void disableTexCoordsVertexArray();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Indices
+    ///////////////////////////////////////////////////////////////////////////////
+    /**
+     * Binds a global indices buffer that can draw up to
+     * gMaxNumberOfQuads quads.
+     */
+    bool bindQuadIndicesBuffer();
+    bool unbindIndicesBuffer();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Getters - for use in Glop building
+    ///////////////////////////////////////////////////////////////////////////////
+    GLuint getUnitQuadVBO() { return mUnitQuadBuffer; }
+    GLuint getQuadListIBO() { return mQuadListIndices; }
+private:
+    MeshState();
+    bool bindMeshBufferInternal(const GLuint buffer);
+    bool bindIndicesBufferInternal(const GLuint buffer);
+
+    GLuint mUnitQuadBuffer;
+
+    GLuint mCurrentBuffer;
+    GLuint mCurrentIndicesBuffer;
+    GLuint mCurrentPixelBuffer;
+
+    const void* mCurrentPositionPointer;
+    GLsizei mCurrentPositionStride;
+    const void* mCurrentTexCoordsPointer;
+    GLsizei mCurrentTexCoordsStride;
+
+    bool mTexCoordsArrayEnabled;
+
+    // Global index buffer
+    GLuint mQuadListIndices;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_MESHSTATE_H
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
new file mode 100644
index 0000000..c23af52
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 "renderstate/PixelBufferState.h"
+
+namespace android {
+namespace uirenderer {
+
+PixelBufferState::PixelBufferState()
+        : mCurrentPixelBuffer(0) {
+}
+
+bool PixelBufferState::bind(GLuint buffer) {
+    if (mCurrentPixelBuffer != buffer) {
+        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
+        mCurrentPixelBuffer = buffer;
+        return true;
+    }
+    return false;
+}
+
+bool PixelBufferState::unbind() {
+    if (mCurrentPixelBuffer) {
+        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+        mCurrentPixelBuffer = 0;
+        return true;
+    }
+    return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
new file mode 100644
index 0000000..8dab21d
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_PIXELBUFFERSTATE_H
+#define RENDERSTATE_PIXELBUFFERSTATE_H
+
+#include <GLES3/gl3.h>
+
+namespace android {
+namespace uirenderer {
+
+class PixelBufferState {
+    friend class Caches; // TODO: move to RenderState
+public:
+    bool bind(GLuint buffer);
+    bool unbind();
+private:
+    PixelBufferState();
+    GLuint mCurrentPixelBuffer;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 3a9a92e..3953ecd 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "RenderState.h"
+#include "renderstate/RenderState.h"
 
 #include "renderthread/CanvasContext.h"
 #include "renderthread/EglManager.h"
+#include "utils/GLUtils.h"
 
 namespace android {
 namespace uirenderer {
 
 RenderState::RenderState(renderthread::RenderThread& thread)
         : mRenderThread(thread)
-        , mCaches(nullptr)
         , mViewportWidth(0)
         , mViewportHeight(0)
         , mFramebuffer(0) {
@@ -31,17 +31,28 @@
 }
 
 RenderState::~RenderState() {
+    LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+            "State object lifecycle not managed correctly");
 }
 
 void RenderState::onGLContextCreated() {
-    // This is delayed because the first access of Caches makes GL calls
-    mCaches = &Caches::getInstance();
-    mCaches->init();
-    mCaches->setRenderState(this);
-    mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
+    LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+            "State object lifecycle not managed correctly");
+    mBlend = new Blend();
+    mMeshState = new MeshState();
+    mScissor = new Scissor();
+    mStencil = new Stencil();
 
-    LOG_ALWAYS_FATAL_IF(scissor().isEnabled(), "scissor used before GL context created");
-    glDisable(GL_SCISSOR_TEST);
+    // This is delayed because the first access of Caches makes GL calls
+    if (!mCaches) {
+        mCaches = &Caches::createInstance(*this);
+    }
+    mCaches->init();
+    mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
+}
+
+static void layerLostGlContext(Layer* layer) {
+    layer->onGlContextLost();
 }
 
 void RenderState::onGLContextDestroyed() {
@@ -76,7 +87,21 @@
         LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size);
     }
 */
+
+    // TODO: reset all cached state in state objects
+    std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
     mAssetAtlas.terminate();
+
+    mCaches->terminate();
+
+    delete mBlend;
+    mBlend = nullptr;
+    delete mMeshState;
+    mMeshState = nullptr;
+    delete mScissor;
+    mScissor = nullptr;
+    delete mStencil;
+    mStencil = nullptr;
 }
 
 void RenderState::setViewport(GLsizei width, GLsizei height) {
@@ -105,17 +130,12 @@
 }
 
 void RenderState::interruptForFunctorInvoke() {
-    if (mCaches->currentProgram) {
-        if (mCaches->currentProgram->isInUse()) {
-            mCaches->currentProgram->remove();
-            mCaches->currentProgram = nullptr;
-        }
-    }
-    mCaches->resetActiveTexture();
-    mCaches->unbindMeshBuffer();
-    mCaches->unbindIndicesBuffer();
-    mCaches->resetVertexPointers();
-    mCaches->disableTexCoordsVertexArray();
+    mCaches->setProgram(nullptr);
+    mCaches->textureState().resetActiveTexture();
+    meshState().unbindMeshBuffer();
+    meshState().unbindIndicesBuffer();
+    meshState().resetVertexPointers();
+    meshState().disableTexCoordsVertexArray();
     debugOverdraw(false, false);
 }
 
@@ -127,26 +147,22 @@
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
     scissor().invalidate();
+    blend().invalidate();
 
-    mCaches->activeTexture(0);
-    mCaches->resetBoundTextures();
-
-    mCaches->blend = true;
-    glEnable(GL_BLEND);
-    glBlendFunc(mCaches->lastSrcMode, mCaches->lastDstMode);
-    glBlendEquation(GL_FUNC_ADD);
+    mCaches->textureState().activateTexture(0);
+    mCaches->textureState().resetBoundTextures();
 }
 
 void RenderState::debugOverdraw(bool enable, bool clear) {
     if (mCaches->debugOverdraw && mFramebuffer == 0) {
         if (clear) {
             scissor().setEnabled(false);
-            mCaches->stencil.clear();
+            stencil().clear();
         }
         if (enable) {
-            mCaches->stencil.enableDebugWrite();
+            stencil().enableDebugWrite();
         } else {
-            mCaches->stencil.disable();
+            stencil().disable();
         }
     }
 }
@@ -161,7 +177,6 @@
     LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
 }
 
-
 class DecStrongTask : public renderthread::RenderTask {
 public:
     DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
@@ -180,5 +195,143 @@
     mRenderThread.queue(new DecStrongTask(object));
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Render
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Not yet supported:
+ *
+ * Textures + coordinates
+ * SkiaShader
+ * RoundRect clipping
+ */
+
+void RenderState::render(const Glop& glop) {
+    const Glop::Mesh& mesh = glop.mesh;
+    const Glop::Fill& fill = glop.fill;
+
+    // ---------------------------------------------
+    // ---------- Program + uniform setup ----------
+    // ---------------------------------------------
+    mCaches->setProgram(fill.program);
+
+    if (fill.colorEnabled) {
+        fill.program->setColor(fill.color);
+    }
+
+    fill.program->set(glop.transform.ortho,
+            glop.transform.modelView,
+            glop.transform.canvas,
+            glop.transform.fudgingOffset);
+
+    // Color filter uniforms
+    if (glop.fill.filterMode == ProgramDescription::kColorBlend) {
+        const FloatColor& color = glop.fill.filter.color;
+        glUniform4f(mCaches->program().getUniform("colorBlend"),
+                color.r, color.g, color.b, color.a);
+    } else if (glop.fill.filterMode == ProgramDescription::kColorMatrix) {
+        glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
+                glop.fill.filter.matrix.matrix);
+        glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
+                glop.fill.filter.matrix.vector);
+    }
+
+    // Round rect clipping uniforms
+    if (glop.roundRectClipState) {
+        // TODO: avoid query, and cache values (or RRCS ptr) in program
+        const RoundRectClipState* state = glop.roundRectClipState;
+        const Rect& innerRect = state->innerRect;
+        glUniform4f(fill.program->getUniform("roundRectInnerRectLTRB"),
+                innerRect.left, innerRect.top,
+                innerRect.right, innerRect.bottom);
+        glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
+                1, GL_FALSE, &state->matrix.data[0]);
+
+        // add half pixel to round out integer rect space to cover pixel centers
+        float roundedOutRadius = state->radius + 0.5f;
+        glUniform1f(fill.program->getUniform("roundRectRadius"),
+                roundedOutRadius);
+    }
+
+    // --------------------------------
+    // ---------- Mesh setup ----------
+    // --------------------------------
+    // vertices
+    const bool force = meshState().bindMeshBufferInternal(mesh.vertexBufferObject)
+            || (mesh.vertices != nullptr);
+    meshState().bindPositionVertexPointer(force, mesh.vertices, mesh.stride);
+
+    // indices
+    meshState().bindIndicesBufferInternal(mesh.indexBufferObject);
+
+    if (mesh.vertexFlags & kTextureCoord_Attrib) {
+        // TODO: to support shaders, increment texture unit
+        mCaches->textureState().activateTexture(0);
+
+        glop.fill.texture->setWrap(GL_CLAMP_TO_EDGE, true);
+        glop.fill.texture->setFilter(glop.fill.textureFilter, true);
+
+        mCaches->textureState().bindTexture(fill.texture->id);
+        meshState().enableTexCoordsVertexArray();
+        meshState().bindTexCoordsVertexPointer(force, mesh.texCoordOffset);
+    } else {
+        meshState().disableTexCoordsVertexArray();
+    }
+    if (mesh.vertexFlags & kColor_Attrib) {
+        LOG_ALWAYS_FATAL("color vertex attribute not yet supported");
+        // TODO: enable color attribute, disable when done
+    }
+    int alphaSlot = -1;
+    if (mesh.vertexFlags & kAlpha_Attrib) {
+        const void* alphaCoords = ((const GLbyte*) glop.mesh.vertices) + kVertexAlphaOffset;
+        alphaSlot = fill.program->getAttrib("vtxAlpha");
+        glEnableVertexAttribArray(alphaSlot);
+        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
+    }
+
+    // ------------------------------------
+    // ---------- GL state setup ----------
+    // ------------------------------------
+    blend().setFactors(glop.blend.src, glop.blend.dst);
+
+    // ------------------------------------
+    // ---------- Actual drawing ----------
+    // ------------------------------------
+    if (mesh.indexBufferObject == meshState().getQuadListIBO()) {
+        // Since the indexed quad list is of limited length, we loop over
+        // the glDrawXXX method while updating the vertex pointer
+        GLsizei elementsCount = mesh.elementCount;
+        const GLbyte* vertices = static_cast<const GLbyte*>(mesh.vertices);
+        while (elementsCount > 0) {
+            GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+
+            // TODO: this double binds on first pass
+            meshState().bindPositionVertexPointer(true, vertices, mesh.stride);
+            glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            elementsCount -= drawCount;
+            vertices += (drawCount / 6) * 4 * mesh.stride;
+        }
+    } else if (mesh.indexBufferObject || mesh.indices) {
+        glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, mesh.indices);
+    } else {
+        glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
+    }
+
+    // -----------------------------------
+    // ---------- Mesh teardown ----------
+    // -----------------------------------
+    if (glop.mesh.vertexFlags & kAlpha_Attrib) {
+        glDisableVertexAttribArray(alphaSlot);
+    }
+}
+
+void RenderState::dump() {
+    blend().dump();
+    meshState().dump();
+    scissor().dump();
+    stencil().dump();
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index b2d5cc5..4fd792c 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -22,12 +22,16 @@
 #include <utils/Mutex.h>
 #include <utils/Functor.h>
 #include <utils/RefBase.h>
-
 #include <private/hwui/DrawGlInfo.h>
+#include <renderstate/Blend.h>
 
 #include "AssetAtlas.h"
 #include "Caches.h"
-#include "Scissor.h"
+#include "Glop.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/Scissor.h"
+#include "renderstate/Stencil.h"
 #include "utils/Macros.h"
 
 namespace android {
@@ -59,10 +63,10 @@
 
     void debugOverdraw(bool enable, bool clear);
 
-    void registerLayer(const Layer* layer) {
+    void registerLayer(Layer* layer) {
         mActiveLayers.insert(layer);
     }
-    void unregisterLayer(const Layer* layer) {
+    void unregisterLayer(Layer* layer) {
         mActiveLayers.erase(layer);
     }
 
@@ -80,9 +84,15 @@
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
 
-    AssetAtlas& assetAtlas() { return mAssetAtlas; }
+    void render(const Glop& glop);
 
-    Scissor& scissor() { return mScissor; }
+    AssetAtlas& assetAtlas() { return mAssetAtlas; }
+    Blend& blend() { return *mBlend; }
+    MeshState& meshState() { return *mMeshState; }
+    Scissor& scissor() { return *mScissor; }
+    Stencil& stencil() { return *mStencil; }
+
+    void dump();
 private:
     friend class renderthread::RenderThread;
     friend class Caches;
@@ -94,12 +104,17 @@
     RenderState(renderthread::RenderThread& thread);
     ~RenderState();
 
-    Scissor mScissor;
 
     renderthread::RenderThread& mRenderThread;
-    Caches* mCaches;
+    Caches* mCaches = nullptr;
+
+    Blend* mBlend = nullptr;
+    MeshState* mMeshState = nullptr;
+    Scissor* mScissor = nullptr;
+    Stencil* mStencil = nullptr;
+
     AssetAtlas mAssetAtlas;
-    std::set<const Layer*> mActiveLayers;
+    std::set<Layer*> mActiveLayers;
     std::set<renderthread::CanvasContext*> mRegisteredContexts;
 
     GLsizei mViewportWidth;
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index ede57be..95dcd18 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "Scissor.h"
+#include "renderstate/Scissor.h"
+
+#include <utils/Log.h>
 
 namespace android {
 namespace uirenderer {
@@ -79,6 +81,11 @@
     reset();
 }
 
+void Scissor::dump() {
+    ALOGD("Scissor: enabled %d, %d %d %d %d",
+            mEnabled, mScissorX, mScissorY, mScissorWidth, mScissorHeight);
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index eabf3a77..b37ec58 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -25,12 +25,13 @@
 class Scissor {
     friend class RenderState;
 public:
-    Scissor();
     bool setEnabled(bool enabled);
     bool set(GLint x, GLint y, GLint width, GLint height);
     void reset();
     bool isEnabled() { return mEnabled; }
+    void dump();
 private:
+    Scissor();
     void invalidate();
     bool mEnabled;
     GLint mScissorX;
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
similarity index 94%
rename from libs/hwui/Stencil.cpp
rename to libs/hwui/renderstate/Stencil.cpp
index f56a02e..cedb233 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
+#include "renderstate/Stencil.h"
+
+#include "Caches.h"
 #include "Debug.h"
 #include "Extensions.h"
 #include "Properties.h"
-#include "Stencil.h"
 
 #include <GLES2/gl2ext.h>
 
@@ -42,7 +44,7 @@
 
 GLenum Stencil::getSmallestStencilFormat() {
 #if !DEBUG_STENCIL
-    const Extensions& extensions = Extensions::getInstance();
+    const Extensions& extensions = Caches::getInstance().extensions();
     if (extensions.has1BitStencil()) {
         return GL_STENCIL_INDEX1_OES;
     } else if (extensions.has4BitStencil()) {
@@ -123,5 +125,9 @@
     }
 }
 
+void Stencil::dump() {
+    ALOGD("Stencil: state %d", mState);
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Stencil.h b/libs/hwui/renderstate/Stencil.h
similarity index 97%
rename from libs/hwui/Stencil.h
rename to libs/hwui/renderstate/Stencil.h
index 20bb955..e4f0f3f 100644
--- a/libs/hwui/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -98,6 +98,12 @@
         return mState == kTest;
     }
 
+    bool isWriteEnabled() {
+        return mState == kWrite;
+    }
+
+    void dump();
+
 private:
     void enable();
 
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
new file mode 100644
index 0000000..1a638d2
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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 <renderstate/TextureState.h>
+
+namespace android {
+namespace uirenderer {
+
+// Must define as many texture units as specified by kTextureUnitsCount
+const GLenum kTextureUnits[] = {
+    GL_TEXTURE0,
+    GL_TEXTURE1,
+    GL_TEXTURE2
+};
+
+TextureState::TextureState()
+        : mTextureUnit(0) {
+    glActiveTexture(kTextureUnits[0]);
+    resetBoundTextures();
+
+    GLint maxTextureUnits;
+    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+    LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
+        "At least %d texture units are required!", kTextureUnitsCount);
+}
+
+void TextureState::activateTexture(GLuint textureUnit) {
+    if (mTextureUnit != textureUnit) {
+        glActiveTexture(kTextureUnits[textureUnit]);
+        mTextureUnit = textureUnit;
+    }
+}
+
+void TextureState::resetActiveTexture() {
+    mTextureUnit = -1;
+}
+
+void TextureState::bindTexture(GLuint texture) {
+    if (mBoundTextures[mTextureUnit] != texture) {
+        glBindTexture(GL_TEXTURE_2D, texture);
+        mBoundTextures[mTextureUnit] = texture;
+    }
+}
+
+void TextureState::bindTexture(GLenum target, GLuint texture) {
+    if (target == GL_TEXTURE_2D) {
+        bindTexture(texture);
+    } else {
+        // GLConsumer directly calls glBindTexture() with
+        // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
+        // since the cached state could be stale
+        glBindTexture(target, texture);
+    }
+}
+
+void TextureState::deleteTexture(GLuint texture) {
+    // When glDeleteTextures() is called on a currently bound texture,
+    // OpenGL ES specifies that the texture is then considered unbound
+    // Consider the following series of calls:
+    //
+    // glGenTextures -> creates texture name 2
+    // glBindTexture(2)
+    // glDeleteTextures(2) -> 2 is now unbound
+    // glGenTextures -> can return 2 again
+    //
+    // If we don't call glBindTexture(2) after the second glGenTextures
+    // call, any texture operation will be performed on the default
+    // texture (name=0)
+
+    unbindTexture(texture);
+
+    glDeleteTextures(1, &texture);
+}
+
+void TextureState::resetBoundTextures() {
+    for (int i = 0; i < kTextureUnitsCount; i++) {
+        mBoundTextures[i] = 0;
+    }
+}
+
+void TextureState::unbindTexture(GLuint texture) {
+    for (int i = 0; i < kTextureUnitsCount; i++) {
+        if (mBoundTextures[i] == texture) {
+            mBoundTextures[i] = 0;
+        }
+    }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
new file mode 100644
index 0000000..5a57b9f
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_TEXTURESTATE_H
+#define RENDERSTATE_TEXTURESTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class TextureState {
+    friend class Caches; // TODO: move to RenderState
+public:
+    /**
+     * Activate the specified texture unit. The texture unit must
+     * be specified using an integer number (0 for GL_TEXTURE0 etc.)
+     */
+    void activateTexture(GLuint textureUnit);
+
+    /**
+     * Invalidate the cached value of the active texture unit.
+     */
+    void resetActiveTexture();
+
+    /**
+     * Binds the specified texture as a GL_TEXTURE_2D texture.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLenum, GLuint).
+     */
+    void bindTexture(GLuint texture);
+
+    /**
+     * Binds the specified texture with the specified render target.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLuint).
+     */
+    void bindTexture(GLenum target, GLuint texture);
+
+    /**
+     * Deletes the specified texture and clears it from the cache
+     * of bound textures.
+     * All textures must be deleted using this method.
+     */
+    void deleteTexture(GLuint texture);
+
+    /**
+     * Signals that the cache of bound textures should be cleared.
+     * Other users of the context may have altered which textures are bound.
+     */
+    void resetBoundTextures();
+
+    /**
+     * Clear the cache of bound textures.
+     */
+    void unbindTexture(GLuint texture);
+private:
+    // total number of texture units available for use
+    static const int kTextureUnitsCount = 3;
+
+    TextureState();
+    GLuint mTextureUnit;
+
+    // Caches texture bindings for the GL_TEXTURE_2D target
+    GLuint mBoundTextures[kTextureUnitsCount];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4d5d8c8..6346479 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -22,9 +22,9 @@
 #include "../Caches.h"
 #include "../DeferredLayerUpdater.h"
 #include "../renderstate/RenderState.h"
+#include "../renderstate/Stencil.h"
 #include "../LayerRenderer.h"
 #include "../OpenGLRenderer.h"
-#include "../Stencil.h"
 
 #include <algorithm>
 #include <private/hwui/DrawGlInfo.h>
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index c4feb41..3afca2f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -22,10 +22,13 @@
 
 #include <cutils/log.h>
 #include <cutils/properties.h>
+#include <EGL/eglext.h>
 
 #define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
 #define GLES_VERSION 2
 
+#define WAIT_FOR_GPU_COMPLETION 0
+
 // Android-specific addition that is used to show when frames began in systrace
 EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
 
@@ -214,9 +217,6 @@
     if (mEglDisplay == EGL_NO_DISPLAY) return;
 
     usePBufferSurface();
-    if (Caches::hasInstance()) {
-        Caches::getInstance().terminate();
-    }
 
     mRenderThread.renderState().onGLContextDestroyed();
     eglDestroyContext(mEglDisplay, mEglContext);
@@ -263,6 +263,14 @@
 
 bool EglManager::swapBuffers(EGLSurface surface) {
     mInFrame = false;
+
+#if WAIT_FOR_GPU_COMPLETION
+    {
+        ATRACE_NAME("Finishing GPU work");
+        fence();
+    }
+#endif
+
     eglSwapBuffers(mEglDisplay, surface);
     EGLint err = eglGetError();
     if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -281,6 +289,13 @@
     return false;
 }
 
+void EglManager::fence() {
+    EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
+    eglClientWaitSyncKHR(mEglDisplay, fence,
+            EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+    eglDestroySyncKHR(mEglDisplay, fence);
+}
+
 void EglManager::cancelFrame() {
     mInFrame = false;
 }
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index e12db3a..b1a18a9 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -55,6 +55,8 @@
 
     void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
 
+    void fence();
+
 private:
     friend class RenderThread;
 
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index a12dac7..b6d2c4d 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -42,7 +42,8 @@
 
 static DisplayListRenderer* startRecording(RenderNode* node) {
     DisplayListRenderer* renderer = new DisplayListRenderer();
-    renderer->setViewport(node->getWidth(), node->getHeight());
+    renderer->setViewport(node->stagingProperties().getWidth(),
+            node->stagingProperties().getHeight());
     renderer->prepare();
     return renderer;
 }
@@ -53,80 +54,213 @@
     delete renderer;
 }
 
-sp<RenderNode> createCard(int x, int y, int width, int height) {
-    sp<RenderNode> node = new RenderNode();
-    node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
-    node->mutateStagingProperties().setElevation(dp(16));
-    node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
-    node->mutateStagingProperties().mutableOutline().setShouldClip(true);
-    node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
+class TreeContentAnimation {
+public:
+    virtual ~TreeContentAnimation() {}
+    virtual int getFrameCount() { return 150; }
+    virtual void createContent(int width, int height, DisplayListRenderer* renderer) = 0;
+    virtual void doFrame(int frameNr) = 0;
 
-    DisplayListRenderer* renderer = startRecording(node.get());
-    renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
-    endRecording(renderer, node.get());
+    template <class T>
+    static void run() {
+        T animation;
 
-    return node;
-}
+        TestContext testContext;
 
-int main(int argc, char* argv[]) {
-    TestContext testContext;
+        // create the native surface
+        const int width = gDisplay.w;
+        const int height = gDisplay.h;
+        sp<Surface> surface = testContext.surface();
 
-    // create the native surface
-    const int width = gDisplay.w;
-    const int height = gDisplay.h;
-    sp<Surface> surface = testContext.surface();
+        RenderNode* rootNode = new RenderNode();
+        rootNode->incStrong(nullptr);
+        rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
+        rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        rootNode->mutateStagingProperties().setClipToBounds(false);
+        rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 
-    RenderNode* rootNode = new RenderNode();
-    rootNode->incStrong(nullptr);
-    rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
-    rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
-    rootNode->mutateStagingProperties().setClipToBounds(false);
-    rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+        ContextFactory factory;
+        std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
+        proxy->loadSystemProperties();
+        proxy->initialize(surface);
+        float lightX = width / 2.0;
+        proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
+                dp(800.0f), 255 * 0.075, 255 * 0.15);
 
-    ContextFactory factory;
-    std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
-    proxy->loadSystemProperties();
-    proxy->initialize(surface);
-    float lightX = width / 2.0;
-    proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
-            dp(800.0f), 255 * 0.075, 255 * 0.15);
+        android::uirenderer::Rect DUMMY;
 
-    android::uirenderer::Rect DUMMY;
+        std::vector< sp<RenderNode> > cards;
 
-    std::vector< sp<RenderNode> > cards;
+        DisplayListRenderer* renderer = startRecording(rootNode);
+        animation.createContent(width, height, renderer);
+        endRecording(renderer, rootNode);
 
-    DisplayListRenderer* renderer = startRecording(rootNode);
-    renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
-    renderer->insertReorderBarrier(true);
+        for (int i = 0; i < 150; i++) {
+            testContext.waitForVsync();
 
-    for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
-        for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
-            sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
-            renderer->drawRenderNode(card.get(), DUMMY, 0);
-            cards.push_back(card);
+            ATRACE_NAME("UI-Draw Frame");
+            animation.doFrame(i);
+            nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
+            proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
         }
+
+        sleep(5);
+
+        rootNode->decStrong(nullptr);
     }
+};
 
-    renderer->insertReorderBarrier(false);
-    endRecording(renderer, rootNode);
+class ShadowGridAnimation : public TreeContentAnimation {
+public:
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, DisplayListRenderer* renderer) override {
+        android::uirenderer::Rect DUMMY;
 
-    for (int i = 0; i < 150; i++) {
-        testContext.waitForVsync();
+        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        renderer->insertReorderBarrier(true);
 
-        ATRACE_NAME("UI-Draw Frame");
+        for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
+            for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
+                sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
+                renderer->drawRenderNode(card.get(), DUMMY, 0);
+                cards.push_back(card);
+            }
+        }
+
+        renderer->insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
         for (size_t ci = 0; ci < cards.size(); ci++) {
-            cards[ci]->mutateStagingProperties().setTranslationX(i);
-            cards[ci]->mutateStagingProperties().setTranslationY(i);
+            cards[ci]->mutateStagingProperties().setTranslationX(frameNr);
+            cards[ci]->mutateStagingProperties().setTranslationY(frameNr);
             cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
         }
-        nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-        proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->mutateStagingProperties().setElevation(dp(16));
+        node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
+        node->mutateStagingProperties().mutableOutline().setShouldClip(true);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
+
+        DisplayListRenderer* renderer = startRecording(node.get());
+        renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+
+class RectGridAnimation : public TreeContentAnimation {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, DisplayListRenderer* renderer) override {
+        android::uirenderer::Rect DUMMY;
+
+        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        renderer->insertReorderBarrier(true);
+
+        card = createCard(40, 40, 200, 200);
+        renderer->drawRenderNode(card.get(), DUMMY, 0);
+
+        renderer->insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
+        card->mutateStagingProperties().setTranslationX(frameNr);
+        card->mutateStagingProperties().setTranslationY(frameNr);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+        DisplayListRenderer* renderer = startRecording(node.get());
+        renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
+
+        float rects[width * height];
+        int index = 0;
+        for (int xOffset = 0; xOffset < width; xOffset+=2) {
+            for (int yOffset = 0; yOffset < height; yOffset+=2) {
+                rects[index++] = xOffset;
+                rects[index++] = yOffset;
+                rects[index++] = xOffset + 1;
+                rects[index++] = yOffset + 1;
+            }
+        }
+        int count = width * height;
+
+        SkPaint paint;
+        paint.setColor(0xff00ffff);
+        renderer->drawRects(rects, count, &paint);
+
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+
+class OvalAnimation : public TreeContentAnimation {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, DisplayListRenderer* renderer) override {
+        android::uirenderer::Rect DUMMY;
+
+        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        renderer->insertReorderBarrier(true);
+
+        card = createCard(40, 40, 400, 400);
+        renderer->drawRenderNode(card.get(), DUMMY, 0);
+
+        renderer->insertReorderBarrier(false);
     }
 
-    sleep(5);
+    void doFrame(int frameNr) override {
+        card->mutateStagingProperties().setTranslationX(frameNr);
+        card->mutateStagingProperties().setTranslationY(frameNr);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-    rootNode->decStrong(nullptr);
+        DisplayListRenderer* renderer = startRecording(node.get());
 
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setColor(0xFF000000);
+        renderer->drawOval(0, 0, width, height, paint);
+
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+
+struct cstr_cmp {
+    bool operator()(const char *a, const char *b) const {
+        return std::strcmp(a, b) < 0;
+    }
+};
+
+typedef void (*testProc)();
+
+std::map<const char*, testProc, cstr_cmp> gTestMap {
+    {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
+    {"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
+    {"oval", TreeContentAnimation::run<OvalAnimation> },
+};
+
+int main(int argc, char* argv[]) {
+    const char* testName = argc > 1 ? argv[1] : "shadowgrid";
+    testProc proc = gTestMap[testName];
+    if(!proc) {
+        printf("Error: couldn't find test %s\n", testName);
+        return 1;
+    }
+    proc();
     printf("Success!\n");
     return 0;
 }
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index 3c30aab..c69b2fd 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -105,6 +105,8 @@
 bool TaskManager::WorkerThread::addTask(TaskWrapper task) {
     if (!isRunning()) {
         run(mName.string(), PRIORITY_DEFAULT);
+    } else if (exitPending()) {
+        return false;
     }
 
     Mutex::Autolock l(mLock);
@@ -120,10 +122,6 @@
 }
 
 void TaskManager::WorkerThread::exit() {
-    {
-        Mutex::Autolock l(mLock);
-        mTasks.clear();
-    }
     requestExit();
     mSignal.signal();
 }
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
index eb4ab64..ec6519c 100644
--- a/libs/hwui/thread/TaskProcessor.h
+++ b/libs/hwui/thread/TaskProcessor.h
@@ -30,9 +30,6 @@
     TaskProcessorBase() { }
     virtual ~TaskProcessorBase() { };
 
-private:
-    friend class TaskManager;
-
     virtual void process(const sp<TaskBase>& task) = 0;
 };
 
@@ -44,9 +41,6 @@
 
     bool add(const sp<Task<T> >& task);
 
-    virtual void onProcess(const sp<Task<T> >& task) = 0;
-
-private:
     virtual void process(const sp<TaskBase>& task) override {
         sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
         // This is the right way to do it but sp<> doesn't play nice
@@ -54,6 +48,8 @@
         onProcess(realTask);
     }
 
+    virtual void onProcess(const sp<Task<T> >& task) = 0;
+
     TaskManager* mManager;
 };
 
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index fe43fdb..eae73a9 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -29,4 +29,8 @@
         friend inline int compare_type(const Type& lhs, const Type& rhs) { return lhs.compare(rhs); } \
         friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
 
+#define REQUIRE_COMPATIBLE_LAYOUT(Type) \
+        static_assert(std::is_standard_layout<Type>::value, \
+        #Type " must have standard layout")
+
 #endif /* MACROS_H */
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index fa0ae03..1a5cbf8 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -16,6 +16,9 @@
 #ifndef PAINT_UTILS_H
 #define PAINT_UTILS_H
 
+#include <SkColorFilter.h>
+#include <SkXfermode.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -34,6 +37,13 @@
         return resultMode;
     }
 
+    static inline GLenum getFilter(const SkPaint* paint) {
+        if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
+            return GL_LINEAR;
+        }
+        return GL_NEAREST;
+    }
+
     // TODO: move to a method on android:Paint? replace with SkPaint::nothingToDraw()?
     static inline bool paintWillNotDraw(const SkPaint& paint) {
         return paint.getAlpha() == 0
@@ -49,6 +59,13 @@
                 && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
     }
 
+    static bool isBlendedShader(const SkShader* shader) {
+        if (shader == nullptr) {
+            return false;
+        }
+        return !shader->isOpaque();
+    }
+
     static bool isBlendedColorFilter(const SkColorFilter* filter) {
         if (filter == nullptr) {
             return false;
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
index 22ac1a9..4135a1c 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -19,7 +19,6 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 /**
  * A class containing a GPS clock timestamp.
@@ -29,7 +28,6 @@
  */
 @SystemApi
 public class GpsClock implements Parcelable {
-    private static final String TAG = "GpsClock";
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -109,17 +107,7 @@
      * Sets the type of time reported.
      */
     public void setType(byte value) {
-        switch (value) {
-            case TYPE_UNKNOWN:
-            case TYPE_GPS_TIME:
-            case TYPE_LOCAL_HW_TIME:
-                mType = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'type': " + value);
-                mType = TYPE_UNKNOWN;
-                break;
-        }
+        mType = value;
     }
 
     /**
@@ -135,7 +123,7 @@
             case TYPE_LOCAL_HW_TIME:
                 return "LocalHwClock";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mType + ">";
         }
     }
 
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index 1c50181..05bcf79 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -19,7 +19,6 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 /**
  * A class representing a GPS satellite measurement, containing raw and computed information.
@@ -28,8 +27,6 @@
  */
 @SystemApi
 public class GpsMeasurement implements Parcelable {
-    private static final String TAG = "GpsMeasurement";
-
     private int mFlags;
     private byte mPrn;
     private double mTimeOffsetInNs;
@@ -140,6 +137,12 @@
     public static final short STATE_TOW_DECODED = (1<<3);
 
     /**
+     * All the GPS receiver state flags.
+     */
+    private static final short STATE_ALL =
+            STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC | STATE_TOW_DECODED;
+
+    /**
      * The state of the 'Accumulated Delta Range' is invalid or unknown.
      */
     public static final short ADR_STATE_UNKNOWN = 0;
@@ -159,6 +162,11 @@
      */
     public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
 
+    /**
+     * All the 'Accumulated Delta Range' flags.
+     */
+    private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+
     // End enumerations in sync with gps.h
 
     GpsMeasurement() {
@@ -263,19 +271,7 @@
      * Sets the sync state.
      */
     public void setState(short value) {
-        switch (value) {
-            case STATE_UNKNOWN:
-            case STATE_BIT_SYNC:
-            case STATE_CODE_LOCK:
-            case STATE_SUBFRAME_SYNC:
-            case STATE_TOW_DECODED:
-                mState = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'sync state': " + value);
-                mState = STATE_UNKNOWN;
-                break;
-        }
+        mState = value;
     }
 
     /**
@@ -283,20 +279,30 @@
      * For internal and logging use only.
      */
     private String getStateString() {
-        switch (mState) {
-            case STATE_UNKNOWN:
-                return "Unknown";
-            case STATE_BIT_SYNC:
-                return "BitSync";
-            case STATE_CODE_LOCK:
-                return "CodeLock";
-            case STATE_SUBFRAME_SYNC:
-                return "SubframeSync";
-            case STATE_TOW_DECODED:
-                return "TowDecoded";
-            default:
-                return "<Invalid>";
+        if (mState == STATE_UNKNOWN) {
+            return "Unknown";
         }
+        StringBuilder builder = new StringBuilder();
+        if ((mState & STATE_CODE_LOCK) == STATE_CODE_LOCK) {
+            builder.append("CodeLock|");
+        }
+        if ((mState & STATE_BIT_SYNC) == STATE_BIT_SYNC) {
+            builder.append("BitSync|");
+        }
+        if ((mState & STATE_SUBFRAME_SYNC) == STATE_SUBFRAME_SYNC) {
+            builder.append("SubframeSync|");
+        }
+        if ((mState & STATE_TOW_DECODED) == STATE_TOW_DECODED) {
+            builder.append("TowDecoded|");
+        }
+        int remainingStates = mState & ~STATE_ALL;
+        if (remainingStates > 0) {
+            builder.append("Other(");
+            builder.append(Integer.toBinaryString(remainingStates));
+            builder.append(")|");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        return builder.toString();
     }
 
     /**
@@ -395,18 +401,7 @@
      * Sets the 'Accumulated Delta Range' state.
      */
     public void setAccumulatedDeltaRangeState(short value) {
-        switch (value) {
-            case ADR_STATE_UNKNOWN:
-            case ADR_STATE_VALID:
-            case ADR_STATE_RESET:
-            case ADR_STATE_CYCLE_SLIP:
-                mAccumulatedDeltaRangeState = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'Accumulated Delta Range state': " + value);
-                mAccumulatedDeltaRangeState = ADR_STATE_UNKNOWN;
-                break;
-        }
+        mAccumulatedDeltaRangeState = value;
     }
 
     /**
@@ -414,18 +409,27 @@
      * For internal and logging use only.
      */
     private String getAccumulatedDeltaRangeStateString() {
-        switch (mAccumulatedDeltaRangeState) {
-            case ADR_STATE_UNKNOWN:
-                return "Unknown";
-            case ADR_STATE_VALID:
-                return "Valid";
-            case ADR_STATE_RESET:
-                return "Reset";
-            case ADR_STATE_CYCLE_SLIP:
-                return "CycleSlip";
-            default:
-                return "<Invalid>";
+        if (mAccumulatedDeltaRangeState == ADR_STATE_UNKNOWN) {
+            return "Unknown";
         }
+        StringBuilder builder = new StringBuilder();
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_VALID) == ADR_STATE_VALID) {
+            builder.append("Valid|");
+        }
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_RESET) == ADR_STATE_RESET) {
+            builder.append("Reset|");
+        }
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_CYCLE_SLIP) == ADR_STATE_CYCLE_SLIP) {
+            builder.append("CycleSlip|");
+        }
+        int remainingStates = mAccumulatedDeltaRangeState & ~ADR_ALL;
+        if (remainingStates > 0) {
+            builder.append("Other(");
+            builder.append(Integer.toBinaryString(remainingStates));
+            builder.append(")|");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        return builder.toString();
     }
 
     /**
@@ -744,17 +748,7 @@
      * Sets the 'loss of lock' status.
      */
     public void setLossOfLock(byte value) {
-        switch (value) {
-            case LOSS_OF_LOCK_UNKNOWN:
-            case LOSS_OF_LOCK_OK:
-            case LOSS_OF_LOCK_CYCLE_SLIP:
-                mLossOfLock = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'loss of lock': " + value);
-                mLossOfLock = LOSS_OF_LOCK_UNKNOWN;
-                break;
-        }
+        mLossOfLock = value;
     }
 
     /**
@@ -770,7 +764,7 @@
             case LOSS_OF_LOCK_CYCLE_SLIP:
                 return "CycleSlip";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mLossOfLock + ">";
         }
     }
 
@@ -919,17 +913,7 @@
      * Sets the 'multi-path' indicator.
      */
     public void setMultipathIndicator(byte value) {
-        switch (value) {
-            case MULTIPATH_INDICATOR_UNKNOWN:
-            case MULTIPATH_INDICATOR_DETECTED:
-            case MULTIPATH_INDICATOR_NOT_USED:
-                mMultipathIndicator = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'muti-path indicator': " + value);
-                mMultipathIndicator = MULTIPATH_INDICATOR_UNKNOWN;
-                break;
-        }
+        mMultipathIndicator = value;
     }
 
     /**
@@ -945,7 +929,7 @@
             case MULTIPATH_INDICATOR_NOT_USED:
                 return "NotUsed";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mMultipathIndicator + ">";
         }
     }
 
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 42f8ee4..b893f3f 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -20,7 +20,6 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 import java.security.InvalidParameterException;
 
@@ -31,7 +30,7 @@
  */
 @SystemApi
 public class GpsNavigationMessage implements Parcelable {
-    private static final String TAG = "GpsNavigationMessage";
+
     private static final byte[] EMPTY_ARRAY = new byte[0];
 
     // The following enumerations must be in sync with the values declared in gps.h
@@ -102,19 +101,7 @@
      * Sets the type of the navigation message.
      */
     public void setType(byte value) {
-        switch (value) {
-            case TYPE_UNKNOWN:
-            case TYPE_L1CA:
-            case TYPE_L2CNAV:
-            case TYPE_L5CNAV:
-            case TYPE_CNAV2:
-                mType = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'type': " + value);
-                mType = TYPE_UNKNOWN;
-                break;
-        }
+        mType = value;
     }
 
     /**
@@ -134,7 +121,7 @@
             case TYPE_CNAV2:
                 return "CNAV-2";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mType + ">";
         }
     }
 
diff --git a/location/java/android/location/GpsSatellite.java b/location/java/android/location/GpsSatellite.java
index 17af4a6..820f5746 100644
--- a/location/java/android/location/GpsSatellite.java
+++ b/location/java/android/location/GpsSatellite.java
@@ -40,13 +40,17 @@
      * cached GpsStatus instance to the client's copy.
      */
     void setStatus(GpsSatellite satellite) {
-        mValid = satellite.mValid;
-        mHasEphemeris = satellite.mHasEphemeris;
-        mHasAlmanac = satellite.mHasAlmanac;
-        mUsedInFix = satellite.mUsedInFix;
-        mSnr = satellite.mSnr;
-        mElevation = satellite.mElevation;
-        mAzimuth = satellite.mAzimuth;
+        if (satellite == null) {
+            mValid = false;
+        } else {
+            mValid = satellite.mValid;
+            mHasEphemeris = satellite.mHasEphemeris;
+            mHasAlmanac = satellite.mHasAlmanac;
+            mUsedInFix = satellite.mUsedInFix;
+            mSnr = satellite.mSnr;
+            mElevation = satellite.mElevation;
+            mAzimuth = satellite.mAzimuth;
+        }
     }
 
     /**
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 4af55a6..323f326 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -16,6 +16,8 @@
 
 package android.location;
 
+import android.util.SparseArray;
+
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
@@ -29,20 +31,24 @@
 
     /* These package private values are modified by the LocationManager class */
     private int mTimeToFirstFix;
-    private GpsSatellite mSatellites[] = new GpsSatellite[NUM_SATELLITES];
+    private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
 
     private final class SatelliteIterator implements Iterator<GpsSatellite> {
 
-        private GpsSatellite[] mSatellites;
-        int mIndex = 0;
+        private final SparseArray<GpsSatellite> mSatellites;
+        private final int mSatellitesCount;
 
-        SatelliteIterator(GpsSatellite[] satellites) {
+        private int mIndex = 0;
+
+        SatelliteIterator(SparseArray<GpsSatellite> satellites) {
             mSatellites = satellites;
+            mSatellitesCount = satellites.size();
         }
 
         public boolean hasNext() {
-            for (int i = mIndex; i < mSatellites.length; i++) {
-                if (mSatellites[i].mValid) {
+            for (; mIndex < mSatellitesCount; ++mIndex) {
+                GpsSatellite satellite = mSatellites.valueAt(mIndex);
+                if (satellite.mValid) {
                     return true;
                 }
             }
@@ -50,8 +56,9 @@
         }
 
         public GpsSatellite next() {
-            while (mIndex < mSatellites.length) {
-                GpsSatellite satellite = mSatellites[mIndex++];
+            while (mIndex < mSatellitesCount) {
+                GpsSatellite satellite = mSatellites.valueAt(mIndex);
+                ++mIndex;
                 if (satellite.mValid) {
                     return satellite;
                 }
@@ -106,7 +113,7 @@
          * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
          * </ul>
          *
-         * When this method is called, the client should call 
+         * When this method is called, the client should call
          * {@link LocationManager#getGpsStatus} to get additional
          * status information.
          *
@@ -127,11 +134,8 @@
         void onNmeaReceived(long timestamp, String nmea);
     }
 
-    GpsStatus() {
-        for (int i = 0; i < mSatellites.length; i++) {
-            mSatellites[i] = new GpsSatellite(i + 1);
-        }
-    }
+    // For API-compat a public ctor() is not available
+    GpsStatus() {}
 
     /**
      * Used internally within {@link LocationManager} to copy GPS status
@@ -141,18 +145,17 @@
     synchronized void setStatus(int svCount, int[] prns, float[] snrs,
             float[] elevations, float[] azimuths, int ephemerisMask,
             int almanacMask, int usedInFixMask) {
-        int i;
+        clearSatellites();
+        for (int i = 0; i < svCount; i++) {
+            int prn = prns[i];
+            int prnShift = (1 << (prn - 1));
+            if (prn > 0 && prn <= NUM_SATELLITES) {
+                GpsSatellite satellite = mSatellites.get(prn);
+                if (satellite == null) {
+                    satellite = new GpsSatellite(prn);
+                    mSatellites.put(prn, satellite);
+                }
 
-        for (i = 0; i < mSatellites.length; i++) {
-            mSatellites[i].mValid = false;
-        }
-        
-        for (i = 0; i < svCount; i++) {
-            int prn = prns[i] - 1;
-            int prnShift = (1 << prn);
-            if (prn >= 0 && prn < mSatellites.length) {
-                GpsSatellite satellite = mSatellites[prn];
-    
                 satellite.mValid = true;
                 satellite.mSnr = snrs[i];
                 satellite.mElevation = elevations[i];
@@ -172,10 +175,38 @@
      */
     void setStatus(GpsStatus status) {
         mTimeToFirstFix = status.getTimeToFirstFix();
+        clearSatellites();
 
-        for (int i = 0; i < mSatellites.length; i++) {
-            mSatellites[i].setStatus(status.mSatellites[i]);
-        } 
+        SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
+        int otherSatellitesCount = otherSatellites.size();
+        int satelliteIndex = 0;
+        // merge both sparse arrays, note that we have already invalidated the elements in the
+        // receiver array
+        for (int i = 0; i < otherSatellitesCount; ++i) {
+            GpsSatellite otherSatellite = otherSatellites.valueAt(i);
+            int otherSatellitePrn = otherSatellite.getPrn();
+
+            int satellitesCount = mSatellites.size();
+            while (satelliteIndex < satellitesCount
+                    && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
+                ++satelliteIndex;
+            }
+
+            if (satelliteIndex < mSatellites.size()) {
+                GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
+                if (satellite.getPrn() == otherSatellitePrn) {
+                    satellite.setStatus(otherSatellite);
+                } else {
+                    satellite = new GpsSatellite(otherSatellitePrn);
+                    satellite.setStatus(otherSatellite);
+                    mSatellites.put(otherSatellitePrn, satellite);
+                }
+            } else {
+                GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
+                satellite.setStatus(otherSatellite);
+                mSatellites.append(otherSatellitePrn, satellite);
+            }
+        }
     }
 
     void setTimeToFirstFix(int ttff) {
@@ -183,7 +214,7 @@
     }
 
     /**
-     * Returns the time required to receive the first fix since the most recent 
+     * Returns the time required to receive the first fix since the most recent
      * restart of the GPS engine.
      *
      * @return time to first fix in milliseconds
@@ -211,4 +242,12 @@
     public int getMaxSatellites() {
         return NUM_SATELLITES;
     }
+
+    private void clearSatellites() {
+        int satellitesCount = mSatellites.size();
+        for (int i = 0; i < satellitesCount; i++) {
+            GpsSatellite satellite = mSatellites.valueAt(i);
+            satellite.mValid = false;
+        }
+    }
 }
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index fcf222b..bf3387b 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -170,6 +170,9 @@
      * Converts a coordinate to a String representation. The outputType
      * may be one of FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
      * The coordinate must be a valid double between -180.0 and 180.0.
+     * This conversion is performed in a method that is dependent on the
+     * default locale, and so is not guaranteed to round-trip with
+     * {@link #convert(String)}.
      *
      * @throws IllegalArgumentException if coordinate is less than
      * -180.0, greater than 180.0, or is not a number.
@@ -217,7 +220,9 @@
     /**
      * Converts a String in one of the formats described by
      * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS into a
-     * double.
+     * double. This conversion is performed in a locale agnostic
+     * method, and so is not guaranteed to round-trip with
+     * {@link #convert(double, int)}.
      *
      * @throws NullPointerException if coordinate is null
      * @throws IllegalArgumentException if the coordinate is not
diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java
new file mode 100644
index 0000000..4808faf
--- /dev/null
+++ b/location/tests/locationtests/src/android/location/GpsStatusTest.java
@@ -0,0 +1,356 @@
+/*
+ * 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.location;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link GpsStatus}.
+ */
+@SmallTest
+public class GpsStatusTest extends TestCase {
+
+    private static final int MAX_VALUE = 250;
+
+    private final Random mRandom = new Random();
+
+    private GpsStatus mStatus;
+    private int mCount;
+    private int[] mPrns;
+    private float[] mSnrs;
+    private float[] mElevations;
+    private float[] mAzimuth;
+    private int mEphemerisMask;
+    private int mAlmanacMask;
+    private int mUsedInFixMask;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mStatus = createGpsStatus();
+        generateSatellitesData(generateInt());
+    }
+
+    public void testEmptyGpsStatus() throws Exception {
+        verifyIsEmpty(mStatus);
+    }
+
+    public void testGpsStatusIterator() throws Exception {
+        generateSatellitesData(2);
+        setSatellites(mStatus);
+        Iterator<GpsSatellite> iterator = mStatus.getSatellites().iterator();
+        assertTrue("hasNext(1)", iterator.hasNext());
+        assertTrue("hasNext(1) does not overflow", iterator.hasNext());
+        GpsSatellite satellite1 = iterator.next();
+        assertNotNull("satellite", satellite1);
+        assertTrue("hasNext(2)", iterator.hasNext());
+        assertTrue("hasNext(2) does not overflow", iterator.hasNext());
+        GpsSatellite satellite2 = iterator.next();
+        assertNotNull("satellite", satellite2);
+        assertFalse("hasNext() no elements", iterator.hasNext());
+    }
+
+    public void testTtff() throws Exception {
+        int testTtff = generateInt();
+        set(mStatus, testTtff);
+        verifyTtff(mStatus, testTtff);
+    }
+
+    public void testCopyTtff() throws Exception {
+        int testTtff = generateInt();
+        verifyTtff(mStatus, 0);
+
+        GpsStatus otherStatus = createGpsStatus();
+        set(otherStatus, testTtff);
+        verifyTtff(otherStatus, testTtff);
+
+        set(mStatus, otherStatus);
+        verifyTtff(mStatus, testTtff);
+    }
+
+    public void testSetSatellites() throws Exception {
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testCopySatellites() throws Exception {
+        verifyIsEmpty(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testOverrideSatellites() throws Exception {
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(mCount, true /* reusePrns */);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddSatellites() throws Exception {
+        int count = 10;
+        generateSatellitesData(count);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddMoreSatellites() throws Exception {
+        int count = 25;
+        generateSatellitesData(count);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count * 2);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddLessSatellites() throws Exception {
+        int count = 25;
+        generateSatellitesData(count * 2);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    private static void verifyIsEmpty(GpsStatus status) {
+        verifySatelliteCount(status, 0);
+        verifyTtff(status, 0);
+    }
+
+    private static void verifySatelliteCount(GpsStatus status, int expectedCount) {
+        int satellites = 0;
+        for (GpsSatellite s : status.getSatellites()) {
+            ++satellites;
+        }
+        assertEquals("GpsStatus::SatelliteCount", expectedCount, satellites);
+    }
+
+    private void verifySatellites(GpsStatus status) {
+        verifySatelliteCount(status, mCount);
+        verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask,
+                mAlmanacMask, mUsedInFixMask);
+    }
+
+    private static void verifySatellites(
+            GpsStatus status,
+            int count,
+            int[] prns,
+            float[] snrs,
+            float[] elevations,
+            float[] azimuth,
+            int ephemerisMask,
+            int almanacMask,
+            int usedInFixMask) {
+        for (int i = 0; i < count; ++i) {
+            int prn = prns[i];
+            GpsSatellite satellite = getSatellite(status, prn);
+            assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
+            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "Elevation"),
+                    elevations[i],
+                    satellite.getElevation());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "Azimuth"),
+                    azimuth[i],
+                    satellite.getAzimuth());
+            int prnShift = 1 << (prn - 1);
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "ephemeris"),
+                    (ephemerisMask & prnShift) != 0,
+                    satellite.hasEphemeris());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "almanac"),
+                    (almanacMask & prnShift) != 0,
+                    satellite.hasAlmanac());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "usedInFix"),
+                    (usedInFixMask & prnShift) != 0,
+                    satellite.usedInFix());
+        }
+    }
+
+    private static void verifyTtff(GpsStatus status, int expectedTtff) {
+        assertEquals("GpsStatus::TTFF", expectedTtff, status.getTimeToFirstFix());
+    }
+
+    private static GpsStatus createGpsStatus() throws Exception {
+        Constructor<GpsStatus>  ctor = GpsStatus.class.getDeclaredConstructor();
+        ctor.setAccessible(true);
+        return ctor.newInstance();
+    }
+
+    private static void set(GpsStatus status, int ttff) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Method setTtff = statusClass.getDeclaredMethod("setTimeToFirstFix", Integer.TYPE);
+        setTtff.setAccessible(true);
+        setTtff.invoke(status, ttff);
+    }
+
+    private static void set(GpsStatus status, GpsStatus statusToSet) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Method setStatus = statusClass.getDeclaredMethod("setStatus", statusClass);
+        setStatus.setAccessible(true);
+        setStatus.invoke(status, statusToSet);
+    }
+
+    private void setSatellites(GpsStatus status) throws Exception {
+        set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
+                mUsedInFixMask);
+    }
+
+    private static void set(
+            GpsStatus status,
+            int count,
+            int[] prns,
+            float[] snrs,
+            float[] elevations,
+            float[] azimuth,
+            int ephemerisMask,
+            int almanacMask,
+            int usedInFixMask) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Class<?> intClass = Integer.TYPE;
+        Class<?> floatArrayClass = Class.forName("[F");
+        Method setStatus = statusClass.getDeclaredMethod(
+                "setStatus",
+                intClass,
+                Class.forName("[I"),
+                floatArrayClass,
+                floatArrayClass,
+                floatArrayClass,
+                intClass,
+                intClass,
+                intClass);
+        setStatus.setAccessible(true);
+        setStatus.invoke(
+                status,
+                count,
+                prns,
+                snrs,
+                elevations,
+                azimuth,
+                ephemerisMask,
+                almanacMask,
+                usedInFixMask);
+    }
+
+    private int generateInt() {
+        return mRandom.nextInt(MAX_VALUE) + 1;
+    }
+
+    private int[] generateIntArray(int count) {
+        Set<Integer> generatedPrns = new HashSet<>();
+        int[] array = new int[count];
+        for(int i = 0; i < count; ++i) {
+            int generated;
+            do {
+                generated = generateInt();
+            } while (generatedPrns.contains(generated));
+            array[i] = generated;
+            generatedPrns.add(generated);
+        }
+        return array;
+    }
+
+    private float[] generateFloatArray(int count) {
+        float[] array = new float[count];
+        for(int i = 0; i < count; ++i) {
+            array[i] = generateInt();
+        }
+        return array;
+    }
+
+    private int generateMask(int[] prns) {
+        int mask = 0;
+        int prnsLength = prns.length;
+        for (int i = 0; i < prnsLength; ++i) {
+            if (mRandom.nextBoolean()) {
+                mask |= 1 << (prns[i] - 1);
+            }
+        }
+        return mask;
+    }
+
+    private void generateSatellitesData(int count) {
+        generateSatellitesData(count, false /* reusePrns */);
+    }
+
+    private void generateSatellitesData(int count, boolean reusePrns) {
+        mCount = count;
+        if (!reusePrns) {
+            mPrns = generateIntArray(count);
+        }
+        mSnrs = generateFloatArray(count);
+        mElevations = generateFloatArray(count);
+        mAzimuth = generateFloatArray(count);
+        mEphemerisMask = generateMask(mPrns);
+        mAlmanacMask = generateMask(mPrns);
+        mUsedInFixMask = generateMask(mPrns);
+    }
+
+    private static GpsSatellite getSatellite(GpsStatus status, int prn) {
+        for (GpsSatellite satellite : status.getSatellites()) {
+            if (satellite.getPrn() == prn) {
+                return satellite;
+            }
+        }
+        return null;
+    }
+
+    private static String getSatelliteAssertInfo(int index, int prn, String param) {
+        return String.format("Satellite::%s [i=%d, prn=%d]", param, index, prn);
+    }
+}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 489f552..ca242e4 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -709,7 +709,13 @@
         }
     }
 
-    /** @hide */
+    /**
+     * @hide
+     * Only use to get which stream type should be used for volume control, NOT for audio playback
+     * (all audio playback APIs are supposed to take AudioAttributes as input parameters)
+     * @param aa non-null AudioAttributes.
+     * @return a valid stream type for volume control that matches the attributes.
+     */
     public static int toLegacyStreamType(AudioAttributes aa) {
         // flags to stream type mapping
         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index b10736b..82da27d 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -36,12 +36,13 @@
     private final int mType;
     private final String mAddress;
 
-    AudioDevicePort(AudioHandle handle, int[] samplingRates, int[] channelMasks,
+    AudioDevicePort(AudioHandle handle, String deviceName,
+            int[] samplingRates, int[] channelMasks,
             int[] formats, AudioGain[] gains, int type, String address) {
         super(handle,
              (AudioManager.isInputDevice(type) == true)  ?
                         AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
-             samplingRates, channelMasks, formats, gains);
+             deviceName, samplingRates, channelMasks, formats, gains);
         mType = type;
         mAddress = address;
     }
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index fbdda3c..540c328 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -45,8 +45,9 @@
      * @param gainRequest
      * @param lossReceived
      * @param flags
+     * @hide
      */
-    AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
+    public AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
             int gainRequest, int lossReceived, int flags) {
         mAttributes = aa == null ? new AudioAttributes.Builder().build() : aa;
         mClientId = clientId == null ? "" : clientId;
@@ -91,7 +92,7 @@
     public int getLossReceived() { return mLossReceived; }
 
     /** @hide */
-    void clearLossReceived() { mLossReceived = 0; }
+    public void clearLossReceived() { mLossReceived = 0; }
 
     /**
      * The flags set in the audio focus request.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9bcf3c8..7084eba 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -46,9 +46,9 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
-import java.util.HashMap;
 import java.util.ArrayList;
-
+import java.util.HashMap;
+import java.util.Iterator;
 
 /**
  * AudioManager provides access to volume and ringer mode control.
@@ -346,6 +346,31 @@
      */
     public static final int ADJUST_SAME = 0;
 
+    /**
+     * Mute the volume. Has no effect if the stream is already muted.
+     *
+     * @see #adjustVolume(int, int)
+     * @see #adjustStreamVolume(int, int, int)
+     */
+    public static final int ADJUST_MUTE = -100;
+
+    /**
+     * Unmute the volume. Has no effect if the stream is not muted.
+     *
+     * @see #adjustVolume(int, int)
+     * @see #adjustStreamVolume(int, int, int)
+     */
+    public static final int ADJUST_UNMUTE = 100;
+
+    /**
+     * Toggle the mute state. If muted the stream will be unmuted. If not muted
+     * the stream will be muted.
+     *
+     * @see #adjustVolume(int, int)
+     * @see #adjustStreamVolume(int, int, int)
+     */
+    public static final int ADJUST_TOGGLE_MUTE = 101;
+
     // Flags should be powers of 2!
 
     /**
@@ -638,8 +663,7 @@
         int keyCode = event.getKeyCode();
         if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
                 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
-                && mVolumeKeyUpTime + AudioService.PLAY_SOUND_DELAY
-                        > SystemClock.uptimeMillis()) {
+                && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
             /*
              * The user has hit another key during the delay (e.g., 300ms)
              * since the last volume key up, so cancel any sounds.
@@ -777,13 +801,17 @@
      * screen is showing. Another example, if music is playing in the background
      * and a call is not active, the music stream will be adjusted.
      * <p>
-     * This method should only be used by applications that replace the platform-wide
-     * management of audio settings or the main telephony application.
-     * <p>This method has no effect if the device implements a fixed volume policy
+     * This method should only be used by applications that replace the
+     * platform-wide management of audio settings or the main telephony
+     * application.
+     * <p>
+     * This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     *
      * @param direction The direction to adjust the volume. One of
-     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
-     *            {@link #ADJUST_SAME}.
+     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
+     *            {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
+     *            {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
      * @param flags One or more flags.
      * @see #adjustSuggestedStreamVolume(int, int, int)
      * @see #adjustStreamVolume(int, int, int)
@@ -808,16 +836,20 @@
      * Adjusts the volume of the most relevant stream, or the given fallback
      * stream.
      * <p>
-     * This method should only be used by applications that replace the platform-wide
-     * management of audio settings or the main telephony application.
-     *
-     * <p>This method has no effect if the device implements a fixed volume policy
+     * This method should only be used by applications that replace the
+     * platform-wide management of audio settings or the main telephony
+     * application.
+     * <p>
+     * This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     *
      * @param direction The direction to adjust the volume. One of
-     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
-     *            {@link #ADJUST_SAME}.
+     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
+     *            {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
+     *            {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
      * @param suggestedStreamType The stream type that will be used if there
-     *            isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is valid here.
+     *            isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
+     *            valid here.
      * @param flags One or more flags.
      * @see #adjustVolume(int, int)
      * @see #adjustStreamVolume(int, int, int)
@@ -1088,77 +1120,81 @@
     }
 
     /**
-     * Solo or unsolo a particular stream. All other streams are muted.
+     * Solo or unsolo a particular stream.
      * <p>
-     * The solo command is protected against client process death: if a process
-     * with an active solo request on a stream dies, all streams that were muted
-     * because of this request will be unmuted automatically.
-     * <p>
-     * The solo requests for a given stream are cumulative: the AudioManager
-     * can receive several solo requests from one or more clients and the stream
-     * will be unsoloed only when the same number of unsolo requests are received.
-     * <p>
-     * For a better user experience, applications MUST unsolo a soloed stream
-     * in onPause() and solo is again in onResume() if appropriate.
-     * <p>This method has no effect if the device implements a fixed volume policy
-     * as indicated by {@link #isVolumeFixed()}.
+     * Do not use. This method has been deprecated and is now a no-op.
+     * {@link #requestAudioFocus} should be used for exclusive audio playback.
      *
      * @param streamType The stream to be soloed/unsoloed.
-     * @param state The required solo state: true for solo ON, false for solo OFF
-     *
+     * @param state The required solo state: true for solo ON, false for solo
+     *            OFF
      * @see #isVolumeFixed()
+     * @deprecated Do not use. If you need exclusive audio playback use
+     *             {@link #requestAudioFocus}.
      */
+    @Deprecated
     public void setStreamSolo(int streamType, boolean state) {
-        IAudioService service = getService();
-        try {
-            service.setStreamSolo(streamType, state, mICallBack);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setStreamSolo", e);
-        }
+        Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
     }
 
     /**
      * Mute or unmute an audio stream.
      * <p>
-     * The mute command is protected against client process death: if a process
-     * with an active mute request on a stream dies, this stream will be unmuted
-     * automatically.
+     * This method should only be used by applications that replace the
+     * platform-wide management of audio settings or the main telephony
+     * application.
      * <p>
-     * The mute requests for a given stream are cumulative: the AudioManager
-     * can receive several mute requests from one or more clients and the stream
-     * will be unmuted only when the same number of unmute requests are received.
-     * <p>
-     * For a better user experience, applications MUST unmute a muted stream
-     * in onPause() and mute is again in onResume() if appropriate.
-     * <p>
-     * This method should only be used by applications that replace the platform-wide
-     * management of audio settings or the main telephony application.
-     * <p>This method has no effect if the device implements a fixed volume policy
+     * This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     * <p>
+     * This method was deprecated in API level 22. Prior to API level 22 this
+     * method had significantly different behavior and should be used carefully.
+     * The following applies only to pre-22 platforms:
+     * <ul>
+     * <li>The mute command is protected against client process death: if a
+     * process with an active mute request on a stream dies, this stream will be
+     * unmuted automatically.</li>
+     * <li>The mute requests for a given stream are cumulative: the AudioManager
+     * can receive several mute requests from one or more clients and the stream
+     * will be unmuted only when the same number of unmute requests are
+     * received.</li>
+     * <li>For a better user experience, applications MUST unmute a muted stream
+     * in onPause() and mute is again in onResume() if appropriate.</li>
+     * </ul>
      *
      * @param streamType The stream to be muted/unmuted.
-     * @param state The required mute state: true for mute ON, false for mute OFF
-     *
+     * @param state The required mute state: true for mute ON, false for mute
+     *            OFF
      * @see #isVolumeFixed()
+     * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
+     *             {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
      */
+    @Deprecated
     public void setStreamMute(int streamType, boolean state) {
-        IAudioService service = getService();
-        try {
-            service.setStreamMute(streamType, state, mICallBack);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setStreamMute", e);
+        Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
+        int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
+        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+            adjustSuggestedStreamVolume(direction, streamType, 0);
+        } else {
+            adjustStreamVolume(streamType, direction, 0);
         }
     }
 
     /**
-     * get stream mute state.
+     * Returns the current mute state for a particular stream.
      *
-     * @hide
+     * @param streamType The stream to get mute state for.
+     * @return The mute state for the given stream.
+     * @see #adjustStreamVolume(int, int, int)
      */
     public boolean isStreamMute(int streamType) {
         IAudioService service = getService();
         try {
-            return service.isStreamMute(streamType);
+            if (mUseMasterVolume) {
+                return service.isMasterMute();
+            } else {
+                return service.isStreamMute(streamType);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in isStreamMute", e);
             return false;
@@ -1166,29 +1202,6 @@
     }
 
     /**
-     * set master mute state.
-     *
-     * @hide
-     */
-    public void setMasterMute(boolean state) {
-        setMasterMute(state, FLAG_SHOW_UI);
-    }
-
-    /**
-     * set master mute state with optional flags.
-     *
-     * @hide
-     */
-    public void setMasterMute(boolean state, int flags) {
-        IAudioService service = getService();
-        try {
-            service.setMasterMute(state, flags, mContext.getOpPackageName(), mICallBack);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMasterMute", e);
-        }
-    }
-
-    /**
      * get master mute state.
      *
      * @hide
@@ -2487,7 +2500,7 @@
             service.requestAudioFocus(new AudioAttributes.Builder()
                         .setInternalLegacyStreamType(streamType).build(),
                     durationHint, mICallBack, null,
-                    MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+                    AudioSystem.IN_VOICE_COMM_FOCUS_ID,
                     mContext.getOpPackageName(),
                     AUDIOFOCUS_FLAG_LOCK,
                     null /* policy token */);
@@ -2505,7 +2518,7 @@
     public void abandonAudioFocusForCall() {
         IAudioService service = getService();
         try {
-            service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+            service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
                     null /*AudioAttributes, legacy behavior*/);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
@@ -3189,10 +3202,10 @@
      * @param name   device name
      * {@hide}
      */
-    public void setWiredDeviceConnectionState(int device, int state, String name) {
+    public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
         IAudioService service = getService();
         try {
-            service.setWiredDeviceConnectionState(device, state, name);
+            service.setWiredDeviceConnectionState(type, state, address, name);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e);
         }
@@ -3588,11 +3601,13 @@
                     newPorts.clear();
                     status = AudioSystem.listAudioPorts(newPorts, portGeneration);
                     if (status != SUCCESS) {
+                        Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
                         return status;
                     }
                     newPatches.clear();
                     status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
                     if (status != SUCCESS) {
+                        Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
                         return status;
                     }
                 } while (patchGeneration[0] != portGeneration[0]);
@@ -3601,20 +3616,35 @@
                     for (int j = 0; j < newPatches.get(i).sources().length; j++) {
                         AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
                                                                    newPorts);
-                        if (portCfg == null) {
-                            return ERROR;
-                        }
                         newPatches.get(i).sources()[j] = portCfg;
                     }
                     for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
                         AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
                                                                    newPorts);
-                        if (portCfg == null) {
-                            return ERROR;
-                        }
                         newPatches.get(i).sinks()[j] = portCfg;
                     }
                 }
+                for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
+                    AudioPatch newPatch = i.next();
+                    boolean hasInvalidPort = false;
+                    for (AudioPortConfig portCfg : newPatch.sources()) {
+                        if (portCfg == null) {
+                            hasInvalidPort = true;
+                            break;
+                        }
+                    }
+                    for (AudioPortConfig portCfg : newPatch.sinks()) {
+                        if (portCfg == null) {
+                            hasInvalidPort = true;
+                            break;
+                        }
+                    }
+                    if (hasInvalidPort) {
+                        // Temporarily remove patches with invalid ports. One who created the patch
+                        // is responsible for dealing with the port change.
+                        i.remove();
+                    }
+                }
 
                 sAudioPortsCached = newPorts;
                 sAudioPatchesCached = newPatches;
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 616bdd1..873c142 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -41,9 +41,6 @@
     public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
             int uid);
 
-    public abstract void setMasterMuteForUid(boolean state, int flags, String callingPackage,
-            IBinder cb, int uid);
-
     public abstract void setRingerModeDelegate(RingerModeDelegate delegate);
 
     public abstract int getRingerModeInternal();
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
index 1500a43..9fac8d1 100644
--- a/media/java/android/media/AudioMixPort.java
+++ b/media/java/android/media/AudioMixPort.java
@@ -26,9 +26,10 @@
 
 public class AudioMixPort extends AudioPort {
 
-    AudioMixPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+    AudioMixPort(AudioHandle handle, int role, String deviceName,
+            int[] samplingRates, int[] channelMasks,
             int[] formats, AudioGain[] gains) {
-        super(handle, role, samplingRates, channelMasks, formats, gains);
+        super(handle, role, deviceName, samplingRates, channelMasks, formats, gains);
     }
 
     /**
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
index 1ab7e89..b046791 100644
--- a/media/java/android/media/AudioPort.java
+++ b/media/java/android/media/AudioPort.java
@@ -15,7 +15,7 @@
  */
 
 package android.media;
-
+import android.util.Slog;
 
 /**
  * An audio port is a node of the audio framework or hardware that can be connected to or
@@ -37,6 +37,7 @@
  * @hide
  */
 public class AudioPort {
+    private static final String TAG = "AudioPort";
 
     /**
      * For use by the audio framework.
@@ -68,16 +69,20 @@
 
     AudioHandle mHandle;
     protected final int mRole;
+    private final String mName;
     private final int[] mSamplingRates;
     private final int[] mChannelMasks;
     private final int[] mFormats;
     private final AudioGain[] mGains;
     private AudioPortConfig mActiveConfig;
 
-    AudioPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+    AudioPort(AudioHandle handle, int role, String name,
+            int[] samplingRates, int[] channelMasks,
             int[] formats, AudioGain[] gains) {
+
         mHandle = handle;
         mRole = role;
+        mName = name;
         mSamplingRates = samplingRates;
         mChannelMasks = channelMasks;
         mFormats = formats;
@@ -96,6 +101,14 @@
     }
 
     /**
+     * Get the human-readable name of this port. Perhaps an internal
+     * designation or an physical device.
+     */
+    public String name() {
+        return mName;
+    }
+
+    /**
      * Get the list of supported sampling rates
      * Empty array if sampling rate is not relevant for this audio port
      */
diff --git a/media/java/android/media/AudioRoutesInfo.java b/media/java/android/media/AudioRoutesInfo.java
index df9fc06..6ae0d46 100644
--- a/media/java/android/media/AudioRoutesInfo.java
+++ b/media/java/android/media/AudioRoutesInfo.java
@@ -25,26 +25,27 @@
  * @hide
  */
 public class AudioRoutesInfo implements Parcelable {
-    static final int MAIN_SPEAKER = 0;
-    static final int MAIN_HEADSET = 1<<0;
-    static final int MAIN_HEADPHONES = 1<<1;
-    static final int MAIN_DOCK_SPEAKERS = 1<<2;
-    static final int MAIN_HDMI = 1<<3;
+    public static final int MAIN_SPEAKER = 0;
+    public static final int MAIN_HEADSET = 1<<0;
+    public static final int MAIN_HEADPHONES = 1<<1;
+    public static final int MAIN_DOCK_SPEAKERS = 1<<2;
+    public static final int MAIN_HDMI = 1<<3;
+    public static final int MAIN_USB = 1<<4;
 
-    CharSequence mBluetoothName;
-    int mMainType = MAIN_SPEAKER;
+    public CharSequence bluetoothName;
+    public int mainType = MAIN_SPEAKER;
 
     public AudioRoutesInfo() {
     }
 
     public AudioRoutesInfo(AudioRoutesInfo o) {
-        mBluetoothName = o.mBluetoothName;
-        mMainType = o.mMainType;
+        bluetoothName = o.bluetoothName;
+        mainType = o.mainType;
     }
 
     AudioRoutesInfo(Parcel src) {
-        mBluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
-        mMainType = src.readInt();
+        bluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+        mainType = src.readInt();
     }
 
     @Override
@@ -54,8 +55,8 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        TextUtils.writeToParcel(mBluetoothName, dest, flags);
-        dest.writeInt(mMainType);
+        TextUtils.writeToParcel(bluetoothName, dest, flags);
+        dest.writeInt(mainType);
     }
 
     public static final Parcelable.Creator<AudioRoutesInfo> CREATOR
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 46ab7e0..787320e 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -16,7 +16,10 @@
 
 package android.media;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.audiopolicy.AudioMix;
+
 import java.util.ArrayList;
 
 /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
@@ -65,6 +68,19 @@
     private static final int NUM_STREAM_TYPES = 10;
     public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
 
+    public static final String[] STREAM_NAMES = new String[] {
+        "STREAM_VOICE_CALL",
+        "STREAM_SYSTEM",
+        "STREAM_RING",
+        "STREAM_MUSIC",
+        "STREAM_ALARM",
+        "STREAM_NOTIFICATION",
+        "STREAM_BLUETOOTH_SCO",
+        "STREAM_SYSTEM_ENFORCED",
+        "STREAM_DTMF",
+        "STREAM_TTS"
+    };
+
     /*
      * Sets the microphone mute on or off.
      *
@@ -534,7 +550,8 @@
     public static final int SYNC_EVENT_NONE = 0;
     public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1;
 
-    public static native int setDeviceConnectionState(int device, int state, String device_address);
+    public static native int setDeviceConnectionState(int device, int state,
+                                                      String device_address, String device_name);
     public static native int getDeviceConnectionState(int device, String device_address);
     public static native int setPhoneState(int state);
     public static native int setForceUse(int usage, int config);
@@ -569,5 +586,93 @@
     public static native int getAudioHwSyncForSession(int sessionId);
 
     public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
+
+
+    // Items shared with audio service
+
+    /**
+     * The delay before playing a sound. This small period exists so the user
+     * can press another key (non-volume keys, too) to have it NOT be audible.
+     * <p>
+     * PhoneWindow will implement this part.
+     */
+    public static final int PLAY_SOUND_DELAY = 300;
+
+    /**
+     * Constant to identify a focus stack entry that is used to hold the focus while the phone
+     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+     * entering and exiting calls.
+     */
+    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+
+    /**
+     * @see AudioManager#setVibrateSetting(int, int)
+     */
+    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
+            int vibrateSetting) {
+
+        // First clear the existing setting. Each vibrate type has two bits in
+        // the value. Note '3' is '11' in binary.
+        existingValue &= ~(3 << (vibrateType * 2));
+
+        // Set into the old value
+        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
+
+        return existingValue;
+    }
+
+    public static int getDefaultStreamVolume(int streamType) {
+        return DEFAULT_STREAM_VOLUME[streamType];
+    }
+
+    public static int[] DEFAULT_STREAM_VOLUME = new int[] {
+        4,  // STREAM_VOICE_CALL
+        7,  // STREAM_SYSTEM
+        5,  // STREAM_RING
+        11, // STREAM_MUSIC
+        6,  // STREAM_ALARM
+        5,  // STREAM_NOTIFICATION
+        7,  // STREAM_BLUETOOTH_SCO
+        7,  // STREAM_SYSTEM_ENFORCED
+        11, // STREAM_DTMF
+        11  // STREAM_TTS
+    };
+
+    public static String streamToString(int stream) {
+        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
+        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
+        return "UNKNOWN_STREAM_" + stream;
+    }
+
+    /** The platform has no specific capabilities */
+    public static final int PLATFORM_DEFAULT = 0;
+    /** The platform is voice call capable (a phone) */
+    public static final int PLATFORM_VOICE = 1;
+    /** The platform is a television or a set-top box */
+    public static final int PLATFORM_TELEVISION = 2;
+
+    /**
+     * Return the platform type that this is running on. One of:
+     * <ul>
+     * <li>{@link #PLATFORM_VOICE}</li>
+     * <li>{@link #PLATFORM_TELEVISION}</li>
+     * <li>{@link #PLATFORM_DEFAULT}</li>
+     * </ul>
+     */
+    public static int getPlatformType(Context context) {
+        if (context.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {
+            return PLATFORM_VOICE;
+        } else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            return PLATFORM_TELEVISION;
+        } else {
+            return PLATFORM_DEFAULT;
+        }
+    }
+
+    public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
+            (1 << STREAM_MUSIC) |
+            (1 << STREAM_RING) |
+            (1 << STREAM_NOTIFICATION) |
+            (1 << STREAM_SYSTEM);
 }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1af0372..caccb6e 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1237,8 +1237,14 @@
 
     /**
      * Flushes the audio data currently queued for playback. Any data that has
-     * not been played back will be discarded.  No-op if not stopped or paused,
+     * been written but not yet presented will be discarded.  No-op if not stopped or paused,
      * or if the track's creation mode is not {@link #MODE_STREAM}.
+     * <BR> Note that although data written but not yet presented is discarded, there is no
+     * guarantee that all of the buffer space formerly used by that data
+     * is available for a subsequent write.
+     * For example, a call to {@link #write(byte[], int, int)} with <code>sizeInBytes</code>
+     * less than or equal to the total buffer size
+     * may return a short actual transfer count.
      */
     public void flush() {
         if (mState == STATE_INITIALIZED) {
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
index ec33c5c..e3680e9 100644
--- a/media/java/android/media/ClosedCaptionRenderer.java
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -154,6 +154,7 @@
 
     private int mMode = MODE_PAINT_ON;
     private int mRollUpSize = 4;
+    private int mPrevCtrlCode = INVALID;
 
     private CCMemory mDisplay = new CCMemory();
     private CCMemory mNonDisplay = new CCMemory();
@@ -260,6 +261,13 @@
 
     private boolean handleCtrlCode(CCData ccData) {
         int ctrlCode = ccData.getCtrlCode();
+
+        if (mPrevCtrlCode != INVALID && mPrevCtrlCode == ctrlCode) {
+            // discard double ctrl codes (but if there's a 3rd one, we still take that)
+            mPrevCtrlCode = INVALID;
+            return true;
+        }
+
         switch(ctrlCode) {
         case RCL:
             // select pop-on style
@@ -325,10 +333,12 @@
             break;
         case INVALID:
         default:
-            // not handled
+            mPrevCtrlCode = INVALID;
             return false;
         }
 
+        mPrevCtrlCode = ctrlCode;
+
         // handled
         return true;
     }
@@ -666,7 +676,7 @@
             if (pac.isIndentPAC()) {
                 moveCursorTo(pac.getRow(), pac.getCol());
             } else {
-                moveCursorToRow(pac.getRow());
+                moveCursorTo(pac.getRow(), 1);
             }
             getLineBuffer(mRow).setPACAt(mCol, pac);
         }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fad3cec..dabd9c2 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -52,16 +52,10 @@
 
     void setMasterVolume(int index, int flags, String callingPackage);
 
-    void setStreamSolo(int streamType, boolean state, IBinder cb);
-
-    void setStreamMute(int streamType, boolean state, IBinder cb);
-
     boolean isStreamMute(int streamType);
 
     void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb);
 
-    void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb);
-
     boolean isMasterMute();
 
     int getStreamVolume(int streamType);
@@ -195,7 +189,7 @@
     IRingtonePlayer getRingtonePlayer();
     int getMasterStreamType();
 
-    void setWiredDeviceConnectionState(int device, int state, String name);
+    void setWiredDeviceConnectionState(int type, int state, String address, String name);
     int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
 
     AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 0d6b91a..53ab264 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -214,6 +214,11 @@
          * the underlying data could be mapped as a pointer in JNI without doing
          * any copies with {@code GetDirectBufferAddress}.</p>
          *
+         * <p>For raw formats, each plane is only guaranteed to contain data
+         * up to the last pixel in the last row. In other words, the stride
+         * after the last row may not be mapped into the buffer. This is a
+         * necessary requirement for any interleaved format.</p>
+         *
          * @return the byte buffer containing the image data for this plane.
          */
         public abstract ByteBuffer getBuffer();
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index e74399c..6ac854f 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -881,8 +881,8 @@
                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
                 return range;
             } catch (IllegalArgumentException e) {
-                // should not be here
-                Log.w(TAG, "could not get supported widths for " + height , e);
+                // height is not supported because there are no suitable widths
+                Log.v(TAG, "could not get supported widths for " + height);
                 throw new IllegalArgumentException("unsupported height");
             }
         }
@@ -925,8 +925,8 @@
                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
                 return range;
             } catch (IllegalArgumentException e) {
-                // should not be here
-                Log.w(TAG, "could not get supported heights for " + width , e);
+                // width is not supported because there are no suitable heights
+                Log.v(TAG, "could not get supported heights for " + width);
                 throw new IllegalArgumentException("unsupported width");
             }
         }
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 958ffab..5285074 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -171,15 +171,15 @@
         }
 
         void updateAudioRoutes(AudioRoutesInfo newRoutes) {
-            if (newRoutes.mMainType != mCurAudioRoutesInfo.mMainType) {
-                mCurAudioRoutesInfo.mMainType = newRoutes.mMainType;
+            if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
+                mCurAudioRoutesInfo.mainType = newRoutes.mainType;
                 int name;
-                if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
-                        || (newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
+                if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
+                        || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
                     name = com.android.internal.R.string.default_audio_route_name_headphones;
-                } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+                } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
                     name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
-                } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
+                } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
                     name = com.android.internal.R.string.default_media_route_name_hdmi;
                 } else {
                     name = com.android.internal.R.string.default_audio_route_name;
@@ -188,21 +188,21 @@
                 dispatchRouteChanged(sStatic.mDefaultAudioVideo);
             }
 
-            final int mainType = mCurAudioRoutesInfo.mMainType;
+            final int mainType = mCurAudioRoutesInfo.mainType;
 
-            if (!TextUtils.equals(newRoutes.mBluetoothName, mCurAudioRoutesInfo.mBluetoothName)) {
-                mCurAudioRoutesInfo.mBluetoothName = newRoutes.mBluetoothName;
-                if (mCurAudioRoutesInfo.mBluetoothName != null) {
+            if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+                mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
+                if (mCurAudioRoutesInfo.bluetoothName != null) {
                     if (sStatic.mBluetoothA2dpRoute == null) {
                         final RouteInfo info = new RouteInfo(sStatic.mSystemCategory);
-                        info.mName = mCurAudioRoutesInfo.mBluetoothName;
+                        info.mName = mCurAudioRoutesInfo.bluetoothName;
                         info.mDescription = sStatic.mResources.getText(
                                 com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
                         info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
                         sStatic.mBluetoothA2dpRoute = info;
                         addRouteStatic(sStatic.mBluetoothA2dpRoute);
                     } else {
-                        sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.mBluetoothName;
+                        sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
                         dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
                     }
                 } else if (sStatic.mBluetoothA2dpRoute != null) {
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 7ea269b..4ea22f9 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -221,14 +221,10 @@
                 mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
                         direction, flags);
             } else if (isMute) {
-                if (down) {
-                    // We need to send two volume events on down, one to mute
-                    // and one to show the UI
+                if (down && keyEvent.getRepeatCount() == 0) {
                     mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                            MediaSessionManager.DIRECTION_MUTE, flags);
+                            AudioManager.ADJUST_TOGGLE_MUTE, flags);
                 }
-                mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                        0 /* direction, causes UI to show on down */, flags);
             }
         }
     }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index a4ef851..b4fff8f 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -59,14 +59,6 @@
     private Context mContext;
 
     /**
-     * Special flag for sending the mute key to dispatchAdjustVolume used by the
-     * system.
-     *
-     * @hide
-     */
-    public static final int DIRECTION_MUTE = -99;
-
-    /**
      * @hide
      */
     public MediaSessionManager(Context context) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 5b92266..bc9722e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -756,8 +756,9 @@
          * </p><p>
          * Note that this sub-directory also supports opening the logo as an asset file in write
          * mode.  Callers can create or replace the primary logo associated with this channel by
-         * opening the asset file and writing the full-size photo contents into it.  When the file
-         * is closed, the image will be parsed, sized down if necessary, and stored.
+         * opening the asset file and writing the full-size photo contents into it. (Make sure there
+         * is no padding around the logo image.) When the file is closed, the image will be parsed,
+         * sized down if necessary, and stored.
          * </p><p>
          * Usage example:
          * <pre>
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 8c478ed..f29be0d 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -310,7 +310,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")");
-                        mSessionCallback.onSessionEvent(eventType, eventArgs);
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onSessionEvent(eventType, eventArgs);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in sending event (event=" + eventType + ")");
                     }
@@ -329,7 +331,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyChannelRetuned");
-                        mSessionCallback.onChannelRetuned(channelUri);
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onChannelRetuned(channelUri);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyChannelRetuned");
                     }
@@ -366,7 +370,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyTracksChanged");
-                        mSessionCallback.onTracksChanged(tracks);
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onTracksChanged(tracks);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyTracksChanged");
                     }
@@ -394,7 +400,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyTrackSelected");
-                        mSessionCallback.onTrackSelected(type, trackId);
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onTrackSelected(type, trackId);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyTrackSelected");
                     }
@@ -415,7 +423,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyVideoAvailable");
-                        mSessionCallback.onVideoAvailable();
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onVideoAvailable();
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyVideoAvailable");
                     }
@@ -447,7 +457,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyVideoUnavailable");
-                        mSessionCallback.onVideoUnavailable(reason);
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onVideoUnavailable(reason);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyVideoUnavailable");
                     }
@@ -486,7 +498,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyContentAllowed");
-                        mSessionCallback.onContentAllowed();
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onContentAllowed();
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyContentAllowed");
                     }
@@ -526,7 +540,9 @@
                 public void run() {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyContentBlocked");
-                        mSessionCallback.onContentBlocked(rating.flattenToString());
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onContentBlocked(rating.flattenToString());
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyContentBlocked");
                     }
@@ -557,7 +573,9 @@
                     try {
                         if (DEBUG) Log.d(TAG, "layoutSurface (l=" + left + ", t=" + top + ", r="
                                 + right + ", b=" + bottom + ",)");
-                        mSessionCallback.onLayoutSurface(left, top, right, bottom);
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onLayoutSurface(left, top, right, bottom);
+                        }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in layoutSurface");
                     }
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 7e68c78..5406130 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -351,7 +351,7 @@
     int bytesPerPixel = 0;
 
     dataSize = ySize = cSize = cStride = 0;
-    int32_t fmt = buffer->format;
+    int32_t fmt = buffer->flexFormat;
 
     bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, readerFormat);
     fmt = applyFormatOverrides(fmt, readerFormat);
@@ -363,18 +363,21 @@
                 (idx == 1) ?
                     buffer->dataCb :
                 buffer->dataCr;
+            // only map until last pixel
             if (idx == 0) {
-                dataSize = buffer->stride * buffer->height;
+                dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
             } else {
-                dataSize = buffer->chromaStride * buffer->height / 2;
+                dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
+                        buffer->chromaStep * (buffer->width / 2 - 1) + 1;
             }
             break;
         // NV21
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             cr = buffer->data + (buffer->stride * buffer->height);
             cb = cr + 1;
-            ySize = buffer->width * buffer->height;
-            cSize = buffer->width * buffer->height / 2;
+            // only map until last pixel
+            ySize = buffer->width * (buffer->height - 1) + buffer->width;
+            cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
 
             pData =
                 (idx == 0) ?
@@ -488,7 +491,7 @@
     int pixelStride = 0;
     ALOG_ASSERT(buffer != NULL, "buffer is NULL");
 
-    int32_t fmt = buffer->format;
+    int32_t fmt = buffer->flexFormat;
 
     fmt = applyFormatOverrides(fmt, readerFormat);
 
@@ -548,7 +551,7 @@
     int rowStride = 0;
     ALOG_ASSERT(buffer != NULL, "buffer is NULL");
 
-    int32_t fmt = buffer->format;
+    int32_t fmt = buffer->flexFormat;
 
     fmt = applyFormatOverrides(fmt, readerFormat);
 
@@ -796,7 +799,7 @@
         return ACQUIRE_NO_BUFFERS;
     }
 
-    if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+    if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
         jniThrowException(env, "java/lang/UnsupportedOperationException",
                 "NV21 format is not supported by ImageReader");
         return -1;
@@ -825,8 +828,10 @@
     }
 
     int bufFmt = buffer->format;
+    if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        bufFmt = buffer->flexFormat;
+    }
     if (imgReaderFmt != bufFmt) {
-
         if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
                 HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
             // Special casing for when producer switches to a format compatible with flexible YUV
@@ -848,7 +853,7 @@
             String8 msg;
             msg.appendFormat("The producer output buffer format 0x%x doesn't "
                     "match the ImageReader's configured buffer format 0x%x.",
-                    buffer->format, ctx->getBufferFormat());
+                    bufFmt, ctx->getBufferFormat());
             jniThrowException(env, "java/lang/UnsupportedOperationException",
                     msg.string());
             return -1;
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index ea33a2f..e101709 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -232,28 +232,28 @@
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-left", key).c_str(),
+                        AStringPrintf("%s-left", key).c_str(),
                         left);
 
                 SetMapInt32(
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-top", key).c_str(),
+                        AStringPrintf("%s-top", key).c_str(),
                         top);
 
                 SetMapInt32(
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-right", key).c_str(),
+                        AStringPrintf("%s-right", key).c_str(),
                         right);
 
                 SetMapInt32(
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-bottom", key).c_str(),
+                        AStringPrintf("%s-bottom", key).c_str(),
                         bottom);
                 break;
             }
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index a8b91d2..a73209b 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -484,6 +484,7 @@
     status_t err = AMediaExtractor_setDataSourceFd(ex, fd, offset, length);
 
     if (err != AMEDIA_OK) {
+        AMediaExtractor_delete(ex);
         return err;
     }
 
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index 7cee066..5e9ec10 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -97,14 +97,18 @@
 
     /** Called on mLooper thread */
     public void enable() {
-        mEnabled = true;
-        updateRequirements();
+        if (!mEnabled) {
+            mEnabled = true;
+            updateRequirements();
+        }
     }
 
     /** Called on mLooper thread */
     public void disable() {
-        mEnabled = false;
-        updateRequirements();
+        if (mEnabled) {
+            mEnabled = false;
+            updateRequirements();
+        }
     }
 
     /** Called on mLooper thread */
@@ -131,16 +135,14 @@
     private void enableProvider(String name, long minTime) {
         ProviderStats stats = mStats.get(name);
 
-        if (stats.available) {
-            if (!stats.requested) {
-                stats.requestTime = SystemClock.elapsedRealtime();
-                stats.requested = true;
-                stats.minTime = minTime;
-                mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
-            } else if (stats.minTime != minTime) {
-                stats.minTime = minTime;
-                mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
-            }
+        if (!stats.requested) {
+            stats.requestTime = SystemClock.elapsedRealtime();
+            stats.requested = true;
+            stats.minTime = minTime;
+            mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
+        } else if (stats.minTime != minTime) {
+            stats.minTime = minTime;
+            mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
         }
     }
 
diff --git a/packages/Keyguard/res/layout/keyguard_host_view.xml b/packages/Keyguard/res/layout/keyguard_host_view.xml
index 3635aff..7291cd4 100644
--- a/packages/Keyguard/res/layout/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_host_view.xml
@@ -26,7 +26,9 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
-    android:clipToPadding="false">
+    android:clipToPadding="false"
+    android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
+                                                  from this view when bouncer is shown -->
 
     <com.android.keyguard.KeyguardSecurityContainer
         android:id="@+id/keyguard_security_container"
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index d8b0c71..c023dc6 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -41,7 +41,8 @@
 
     private static CharSequence mSeparator;
 
-    private LockPatternUtils mLockPatternUtils;
+    private final boolean mIsEmergencyCallCapable;
+
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@@ -78,7 +79,8 @@
 
     public CarrierText(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mLockPatternUtils = new LockPatternUtils(mContext);
+        mIsEmergencyCallCapable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
         boolean useAllCaps;
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 attrs, R.styleable.CarrierText, 0, 0);
@@ -222,7 +224,7 @@
      */
     private CharSequence makeCarrierStringOnEmergencyCapable(
             CharSequence simMessage, CharSequence emergencyCallMessage) {
-        if (mLockPatternUtils.isEmergencyCallCapable()) {
+        if (mIsEmergencyCallCapable) {
             return concatenate(simMessage, emergencyCallMessage);
         }
         return simMessage;
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 50ac261..3627e3e 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -21,7 +21,7 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.telephony.TelephonyManager;
+import android.telecom.TelecomManager;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.Button;
@@ -50,8 +50,17 @@
             updateEmergencyCallButton();
         }
     };
+
+    public interface EmergencyButtonCallback {
+        public void onEmergencyButtonClickedWhenInCall();
+    }
+
     private LockPatternUtils mLockPatternUtils;
     private PowerManager mPowerManager;
+    private EmergencyButtonCallback mEmergencyButtonCallback;
+
+    private final boolean mIsVoiceCapable;
+    private final boolean mEnableEmergencyCallWhileSimLocked;
 
     public EmergencyButton(Context context) {
         this(context, null);
@@ -59,6 +68,10 @@
 
     public EmergencyButton(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mIsVoiceCapable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
+        mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
     }
 
     @Override
@@ -93,8 +106,11 @@
         // TODO: implement a shorter timeout once new PowerManager API is ready.
         // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
         mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
-        if (mLockPatternUtils.isInCall()) {
-            mLockPatternUtils.resumeCall();
+        if (isInCall()) {
+            resumeCall();
+            if (mEmergencyButtonCallback != null) {
+                mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
+            }
         } else {
             final boolean bypassHandler = true;
             KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
@@ -107,21 +123,57 @@
     }
 
     private void updateEmergencyCallButton() {
-        boolean enabled = false;
-        if (mLockPatternUtils.isInCall()) {
-            enabled = true; // always show "return to call" if phone is off-hook
-        } else if (mLockPatternUtils.isEmergencyCallCapable()) {
-            final boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimPinVoiceSecure();
-            if (simLocked) {
-                // Some countries can't handle emergency calls while SIM is locked.
-                enabled = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
+        boolean visible = false;
+        if (mIsVoiceCapable) {
+            // Emergency calling requires voice capability.
+            if (isInCall()) {
+                visible = true; // always show "return to call" if phone is off-hook
             } else {
-                // True if we need to show a secure screen (pin/pattern/SIM pin/SIM puk);
-                // hides emergency button on "Slide" screen if device is not secure.
-                enabled = mLockPatternUtils.isSecure();
+                final boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext)
+                        .isSimPinVoiceSecure();
+                if (simLocked) {
+                    // Some countries can't handle emergency calls while SIM is locked.
+                    visible = mEnableEmergencyCallWhileSimLocked;
+                } else {
+                    // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
+                    visible = mLockPatternUtils.isSecure();
+                }
             }
         }
-        mLockPatternUtils.updateEmergencyCallButtonState(this, enabled, false);
+        if (visible) {
+            setVisibility(View.VISIBLE);
+
+            int textId;
+            if (isInCall()) {
+                textId = com.android.internal.R.string.lockscreen_return_to_call;
+            } else {
+                textId = com.android.internal.R.string.lockscreen_emergency_call;
+            }
+            setText(textId);
+        } else {
+            setVisibility(View.GONE);
+        }
     }
 
+    public void setCallback(EmergencyButtonCallback callback) {
+        mEmergencyButtonCallback = callback;
+    }
+
+    /**
+     * Resumes a call in progress.
+     */
+    private void resumeCall() {
+        getTelecommManager().showInCallScreen(false);
+    }
+
+    /**
+     * @return {@code true} if there is a call currently in progress.
+     */
+    private boolean isInCall() {
+        return getTelecommManager().isInCall();
+    }
+
+    private TelecomManager getTelecommManager() {
+        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index b03176c..b2e4728 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -32,7 +32,7 @@
  * Base class for PIN and password unlock screens.
  */
 public abstract class KeyguardAbsKeyInputView extends LinearLayout
-        implements KeyguardSecurityView {
+        implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
     protected KeyguardSecurityCallback mCallback;
     protected LockPatternUtils mLockPatternUtils;
     protected SecurityMessageDisplay mSecurityMessageDisplay;
@@ -85,6 +85,15 @@
         mLockPatternUtils = new LockPatternUtils(mContext);
         mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
+
+        EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button);
+        if (button != null) {
+            button.setCallback(this);
+        }
+    }
+
+    public void onEmergencyButtonClickedWhenInCall() {
+        mCallback.reset();
     }
 
     /*
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index c7bc04d..10ce426 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -153,6 +154,16 @@
         return false;
     }
 
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+            event.getText().add(mSecurityContainer.getCurrentSecurityModeContentDescription());
+            return true;
+        } else {
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+    }
+
     protected KeyguardSecurityContainer getSecurityContainer() {
         return mSecurityContainer;
     }
@@ -185,6 +196,11 @@
     }
 
     @Override
+    public void reset() {
+        mViewMediatorCallback.resetKeyguard();
+    }
+
+    @Override
     public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
         if (mViewMediatorCallback != null) {
             mViewMediatorCallback.setNeedsInput(needsInput);
@@ -416,6 +432,4 @@
     public SecurityMode getCurrentSecurityMode() {
         return mSecurityContainer.getCurrentSecurityMode();
     }
-
-
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index dfea166..845d53a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -90,9 +90,11 @@
         post(new Runnable() {
             @Override
             public void run() {
-                mPasswordEntry.requestFocus();
-                if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
-                    mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+                if (isShown()) {
+                    mPasswordEntry.requestFocus();
+                    if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
+                        mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+                    }
                 }
             }
         });
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 62f1b69..9aa5729 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -38,7 +38,8 @@
 import java.util.List;
 
 public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
-        AppearAnimationCreator<LockPatternView.CellState> {
+        AppearAnimationCreator<LockPatternView.CellState>,
+        EmergencyButton.EmergencyButtonCallback {
 
     private static final String TAG = "SecurityPatternView";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -140,6 +141,15 @@
         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
         mContainer = (ViewGroup) findViewById(R.id.container);
         mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area);
+
+        EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button);
+        if (button != null) {
+            button.setCallback(this);
+        }
+    }
+
+    public void onEmergencyButtonClickedWhenInCall() {
+        mCallback.reset();
     }
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
index 8bb8805..5877bc8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -40,4 +40,8 @@
      */
     void reportUnlockAttempt(boolean success);
 
+    /**
+     * Resets the keyguard view.
+     */
+    void reset();
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 61eef48..41ec3b0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -55,6 +55,7 @@
         public void userActivity();
         public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
         public void finish();
+        public void reset();
     }
 
     public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
@@ -111,6 +112,14 @@
         }
     }
 
+    public CharSequence getCurrentSecurityModeContentDescription() {
+        View v = (View) getSecurityView(mCurrentSecuritySelection);
+        if (v != null) {
+            return v.getContentDescription();
+        }
+        return "";
+    }
+
     private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
         final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
         KeyguardSecurityView view = null;
@@ -406,7 +415,6 @@
     }
 
     private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
-
         public void userActivity() {
             if (mSecurityCallback != null) {
                 mSecurityCallback.userActivity();
@@ -431,6 +439,9 @@
             }
         }
 
+        public void reset() {
+            mSecurityCallback.reset();
+        }
     };
 
     // The following is used to ignore callbacks from SecurityViews that are no longer current
@@ -445,6 +456,8 @@
         public boolean isVerifyUnlockOnly() { return false; }
         @Override
         public void dismiss(boolean securityVerified) { }
+        @Override
+        public void reset() {}
     };
 
     private int getSecurityViewIdForMode(SecurityMode securityMode) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 107f417..3eb31ad 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -17,20 +17,16 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.widget.LockPatternUtils;
 
-import java.util.List;
-
 public class KeyguardSecurityModel {
 
     /**
-     * The different types of security available for {@link Mode#UnlockScreen}.
-     * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
+     * The different types of security available.
+     * @see KeyguardSecurityContainer#showSecurityScreen
      */
     public enum SecurityMode {
         Invalid, // NULL state
@@ -42,12 +38,16 @@
         SimPuk // Unlock by entering a sim puk
     }
 
-    private Context mContext;
+    private final Context mContext;
+    private final boolean mIsPukScreenAvailable;
+
     private LockPatternUtils mLockPatternUtils;
 
     KeyguardSecurityModel(Context context) {
         mContext = context;
         mLockPatternUtils = new LockPatternUtils(context);
+        mIsPukScreenAvailable = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enable_puk_unlock_screen);
     }
 
     void setLockPatternUtils(LockPatternUtils utils) {
@@ -56,39 +56,35 @@
 
     SecurityMode getSecurityMode() {
         KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        SecurityMode mode = SecurityMode.None;
+
         if (SubscriptionManager.isValidSubscriptionId(
                 monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED))) {
-            mode = SecurityMode.SimPin;
-        } else if (SubscriptionManager.isValidSubscriptionId(
-                    monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))
-                && mLockPatternUtils.isPukUnlockScreenEnable()) {
-            mode = SecurityMode.SimPuk;
-        } else {
-            final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
-            switch (security) {
-                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
-                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
-                            SecurityMode.PIN : SecurityMode.None;
-                    break;
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
-                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
-                            SecurityMode.Password : SecurityMode.None;
-                    break;
-
-                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
-                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
-                    mode = mLockPatternUtils.isLockPatternEnabled() ?
-                            SecurityMode.Pattern : SecurityMode.None;
-                    break;
-
-                default:
-                    throw new IllegalStateException("Unknown security quality:" + security);
-            }
+            return SecurityMode.SimPin;
         }
-        return mode;
+
+        if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId(
+                monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))) {
+            return SecurityMode.SimPuk;
+        }
+
+        final int security = mLockPatternUtils.getActivePasswordQuality();
+        switch (security) {
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
+                return SecurityMode.PIN;
+
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+                return SecurityMode.Password;
+
+            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+                return SecurityMode.Pattern;
+            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
+                return SecurityMode.None;
+
+            default:
+                throw new IllegalStateException("Unknown security quality:" + security);
+        }
     }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java b/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
index 6497f46..67ddcfa 100644
--- a/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
@@ -28,9 +28,15 @@
 import android.graphics.Typeface;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.InputType;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
@@ -176,6 +182,7 @@
 
     public void append(char c) {
         int visibleChars = mTextChars.size();
+        String textbefore = mText;
         mText = mText + c;
         int newLength = mText.length();
         CharState charState;
@@ -196,6 +203,7 @@
             }
         }
         userActivity();
+        sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length(), 0, 1);
     }
 
     private void userActivity() {
@@ -204,12 +212,14 @@
 
     public void deleteLastChar() {
         int length = mText.length();
+        String textbefore = mText;
         if (length > 0) {
             mText = mText.substring(0, length - 1);
             CharState charState = mTextChars.get(length - 1);
             charState.startRemoveAnimation(0, 0);
         }
         userActivity();
+        sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
     }
 
     public String getText() {
@@ -229,6 +239,7 @@
     }
 
     public void reset(boolean animated) {
+        String textbefore = mText;
         mText = "";
         int length = mTextChars.size();
         int middleIndex = (length - 1) / 2;
@@ -256,6 +267,71 @@
         if (!animated) {
             mTextChars.clear();
         }
+        sendAccessibilityEventTypeViewTextChanged(textbefore, 0, textbefore.length(), 0);
+    }
+
+    void sendAccessibilityEventTypeViewTextChanged(String beforeText, int fromIndex,
+                                                   int removedCount, int addedCount) {
+        if (AccessibilityManager.getInstance(mContext).isEnabled() &&
+                (isFocused() || isSelected() && isShown())) {
+            if (!shouldSpeakPasswordsForAccessibility()) {
+                beforeText = null;
+            }
+            AccessibilityEvent event =
+                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+            event.setFromIndex(fromIndex);
+            event.setRemovedCount(removedCount);
+            event.setAddedCount(addedCount);
+            event.setBeforeText(beforeText);
+            event.setPassword(true);
+            sendAccessibilityEventUnchecked(event);
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+
+        event.setClassName(PasswordTextView.class.getName());
+        event.setPassword(true);
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
+
+        if (shouldSpeakPasswordsForAccessibility()) {
+            final CharSequence text = mText;
+            if (!TextUtils.isEmpty(text)) {
+                event.getText().add(text);
+            }
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+
+        info.setClassName(PasswordTextView.class.getName());
+        info.setPassword(true);
+
+        if (shouldSpeakPasswordsForAccessibility()) {
+            info.setText(mText);
+        }
+
+        info.setEditable(true);
+
+        info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+    }
+
+    /**
+     * @return true if the user has explicitly allowed accessibility services
+     * to speak passwords.
+     */
+    private boolean shouldSpeakPasswordsForAccessibility() {
+        return (Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0,
+                UserHandle.USER_CURRENT_OR_SELF) == 1);
     }
 
     private class CharState {
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
index f327078..5bbcc8c 100644
--- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -62,6 +62,11 @@
     void readyForKeyguardDone();
 
     /**
+     * Reset the keyguard and bouncer.
+     */
+    void resetKeyguard();
+
+    /**
      * Play the "device trusted" sound.
      */
     void playTrustedSound();
diff --git a/packages/PrintSpooler/res/layout/print_activity_controls.xml b/packages/PrintSpooler/res/layout/print_activity_controls.xml
index 0bf64aa..a87afe0 100644
--- a/packages/PrintSpooler/res/layout/print_activity_controls.xml
+++ b/packages/PrintSpooler/res/layout/print_activity_controls.xml
@@ -159,6 +159,34 @@
                 android:layout_marginEnd="16dip"
                 android:orientation="vertical">
 
+                <!-- Duplex -->
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dip"
+                    android:layout_marginStart="12dip"
+                    android:textAppearance="?android:attr/textAppearanceSmall"
+                    android:labelFor="@+id/duplex_spinner"
+                    android:text="@string/label_duplex">
+                </TextView>
+
+                <Spinner
+                    android:id="@+id/duplex_spinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="4dip">
+                </Spinner>
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="16dip"
+                android:layout_marginEnd="16dip"
+                android:orientation="vertical">
+
                 <!-- Range options -->
 
                 <TextView
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 1a840e3..169710a 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papiergrootte"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papiergrootte:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kleur"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Oriëntasie"</string>
     <string name="label_pages" msgid="7768589729282182230">"Bladsye"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Al <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Swart en wit"</item>
     <item msgid="2762241247228983754">"Kleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Geen"</item>
+    <item msgid="7296563835355641719">"Lang rand"</item>
+    <item msgid="79513688117503758">"Kort rand"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Landskap"</item>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index 683d585..7d9b5f3 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"የወረቀት መጠን"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"የወረቀት መጠን፦"</string>
     <string name="label_color" msgid="1108690305218188969">"ቀለም"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"አቀማመጠ ገፅ"</string>
     <string name="label_pages" msgid="7768589729282182230">"ገፆች"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ሁሉም <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -33,7 +34,7 @@
     <string name="install_for_print_preview" msgid="6366303997385509332">"ለቅድመ-እይታ የፒ ዲ ኤፍ መመልከቻ ይጫኑ"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"የአታሚ መተግበሪያ ተበላሽቷል"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"የህትመት ስራን በማመንጨት ላይ"</string>
-    <string name="save_as_pdf" msgid="5718454119847596853">"እንደ ፒዲኤፍ አስቀምጥ"</string>
+    <string name="save_as_pdf" msgid="5718454119847596853">"እንደ PDF አስቀምጥ"</string>
     <string name="all_printers" msgid="5018829726861876202">"ሁሉም አታሚዎች…"</string>
     <string name="print_dialog" msgid="32628687461331979">"የህትመት መገናኛ"</string>
     <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ጥቁር እና ነጭ"</item>
     <item msgid="2762241247228983754">"ቀለም"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ምንም"</item>
+    <item msgid="7296563835355641719">"ረጅም ጠርዝ"</item>
+    <item msgid="79513688117503758">"አጭር ጠርዝ"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"የቁም"</item>
     <item msgid="3199660090246166812">"የወርድ"</item>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 0a7d301..217d070 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"حجم الورق"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"حجم الورق:"</string>
     <string name="label_color" msgid="1108690305218188969">"ألوان"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"مزدوج"</string>
     <string name="label_orientation" msgid="2853142581990496477">"الاتجاه"</string>
     <string name="label_pages" msgid="7768589729282182230">"الصفحات"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"جميع الصفحات وعددها <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"أبيض وأسود"</item>
     <item msgid="2762241247228983754">"ملونة"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"لا شيء"</item>
+    <item msgid="7296563835355641719">"حافة طويلة"</item>
+    <item msgid="79513688117503758">"حافة قصيرة"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"عمودي"</item>
     <item msgid="3199660090246166812">"أفقي"</item>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 8792349..c84f47d 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Размер на хартията"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер на хартията:"</string>
     <string name="label_color" msgid="1108690305218188969">"Цвят"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Двустранен режим"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страници"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Всички <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Черно-бяло"</item>
     <item msgid="2762241247228983754">"Цветно"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Без"</item>
+    <item msgid="7296563835355641719">"Дълъг ръб"</item>
+    <item msgid="79513688117503758">"Къс ръб"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Вертикално"</item>
     <item msgid="3199660090246166812">"Хоризонтално"</item>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 5c5fabf..6e03179 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"কাগজের আকার"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"কাগজের আকার:"</string>
     <string name="label_color" msgid="1108690305218188969">"রঙ"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"দ্বৈত"</string>
     <string name="label_orientation" msgid="2853142581990496477">"সজ্জা"</string>
     <string name="label_pages" msgid="7768589729282182230">"পৃষ্ঠাগুলি"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"সমস্ত <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"কালো এবং সাদা"</item>
     <item msgid="2762241247228983754">"রঙ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"কোনো কিছুই নয়"</item>
+    <item msgid="7296563835355641719">"দীর্ঘ প্রান্ত"</item>
+    <item msgid="79513688117503758">"সংক্ষিপ্ত প্রান্ত"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"প্রতিকৃতি"</item>
     <item msgid="3199660090246166812">"ভূদৃশ্য"</item>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index a9677cb..0ecaf1a 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Mida del paper"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Mida del paper:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dúplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientació"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pàgines"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Totes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Blanc i negre"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Cap"</item>
+    <item msgid="7296563835355641719">"Costat llarg"</item>
+    <item msgid="79513688117503758">"Costat curt"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horitzontal"</item>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 791e485..f26c21c 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Velikost papíru"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Velikost papíru:"</string>
     <string name="label_color" msgid="1108690305218188969">"Barva"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Oboustranně"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientace"</string>
     <string name="label_pages" msgid="7768589729282182230">"Stránky"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Vše: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Černobíle"</item>
     <item msgid="2762241247228983754">"Barevně"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Žádné"</item>
+    <item msgid="7296563835355641719">"Dlouhý okraj"</item>
+    <item msgid="79513688117503758">"Krátký okraj"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Na výšku"</item>
     <item msgid="3199660090246166812">"Na šířku"</item>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index c4a383e..339485a 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papirstørrelse"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papirstørrelse:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farve"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sider"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Sort/hvid"</item>
     <item msgid="2762241247228983754">"Farve"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ingen"</item>
+    <item msgid="7296563835355641719">"Den lange led"</item>
+    <item msgid="79513688117503758">"Den korte led"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stående"</item>
     <item msgid="3199660090246166812">"Liggende"</item>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 43be3dc..d1ff80a 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papierformat"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papierformat:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farbe"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ausrichtung"</string>
     <string name="label_pages" msgid="7768589729282182230">"Seiten"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Schwarz-weiß"</item>
     <item msgid="2762241247228983754">"Farbe"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ohne"</item>
+    <item msgid="7296563835355641719">"Lange Seite"</item>
+    <item msgid="79513688117503758">"Kurze Seite"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Hochformat"</item>
     <item msgid="3199660090246166812">"Querformat"</item>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 25f609b..7181402 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Μεγέθος χαρτιού"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Μέγεθος χαρτιού:"</string>
     <string name="label_color" msgid="1108690305218188969">"Χρώμα"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Δύο πλευρές"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Προσανατολισμός"</string>
     <string name="label_pages" msgid="7768589729282182230">"Σελίδες"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Και οι <xliff:g id="PAGE_COUNT">%1$s</xliff:g> σελίδες"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Ασπρόμαυρο"</item>
     <item msgid="2762241247228983754">"Χρώμα"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Κανένα"</item>
+    <item msgid="7296563835355641719">"Μεγάλη πλευρά"</item>
+    <item msgid="79513688117503758">"Μικρή πλευρά"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Πορτραίτο"</item>
     <item msgid="3199660090246166812">"Οριζόντια"</item>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 2198c7a..56b97b9 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paper size"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paper size:"</string>
     <string name="label_color" msgid="1108690305218188969">"Colour"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"All <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Black &amp; White"</item>
     <item msgid="2762241247228983754">"Colour"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"None"</item>
+    <item msgid="7296563835355641719">"Long edge"</item>
+    <item msgid="79513688117503758">"Short edge"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Landscape"</item>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 2198c7a..56b97b9 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paper size"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paper size:"</string>
     <string name="label_color" msgid="1108690305218188969">"Colour"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"All <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Black &amp; White"</item>
     <item msgid="2762241247228983754">"Colour"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"None"</item>
+    <item msgid="7296563835355641719">"Long edge"</item>
+    <item msgid="79513688117503758">"Short edge"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Landscape"</item>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index e194f55..0229b9c 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Tamaño del papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño de papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Doble faz"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Blanco y negro"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ninguno"</item>
+    <item msgid="7296563835355641719">"Borde largo"</item>
+    <item msgid="79513688117503758">"Borde corto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index b0ab529..87ecfe9 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Tamaño del papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño del papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Doble cara"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Blanco y negro"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ninguna"</item>
+    <item msgid="7296563835355641719">"Borde largo"</item>
+    <item msgid="79513688117503758">"Borde corto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 6e75bbb..5ee0070 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paberi suurus"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paberi suurus:"</string>
     <string name="label_color" msgid="1108690305218188969">"Värv"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dupleksrežiim"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Suund"</string>
     <string name="label_pages" msgid="7768589729282182230">"Lehed"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Kõik <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Mustvalge"</item>
     <item msgid="2762241247228983754">"Värv"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Puudub"</item>
+    <item msgid="7296563835355641719">"Pikk serv"</item>
+    <item msgid="79513688117503758">"Lühike serv"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertikaalpaigutus"</item>
     <item msgid="3199660090246166812">"Horisontaalpaigutus"</item>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 4f0f8fc..4357bf4 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paperaren tamaina"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paperaren tamaina:"</string>
     <string name="label_color" msgid="1108690305218188969">"Koloretan"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Bikoitza"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientazioa"</string>
     <string name="label_pages" msgid="7768589729282182230">"Orriak"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> orriak"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Zuri-beltza"</item>
     <item msgid="2762241247228983754">"Koloretakoa"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Bat ere ez"</item>
+    <item msgid="7296563835355641719">"Ertz luzetik"</item>
+    <item msgid="79513688117503758">"Ertz laburretik"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Bertikala"</item>
     <item msgid="3199660090246166812">"Horizontala"</item>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index d35a063..e205050 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"اندازه کاغذ"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"اندازه کاغذ:"</string>
     <string name="label_color" msgid="1108690305218188969">"رنگی"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"دوبلکس"</string>
     <string name="label_orientation" msgid="2853142581990496477">"جهت"</string>
     <string name="label_pages" msgid="7768589729282182230">"صفحه‌ها"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"همه <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"سیاه و سفید"</item>
     <item msgid="2762241247228983754">"رنگی"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"هیچ‌کدام"</item>
+    <item msgid="7296563835355641719">"طول"</item>
+    <item msgid="79513688117503758">"عرض"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"عمودی"</item>
     <item msgid="3199660090246166812">"افقی"</item>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 8e540f9..8af0bb4 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paperikoko"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paperikoko:"</string>
     <string name="label_color" msgid="1108690305218188969">"Väri"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Suunta"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sivut"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Kaikki <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Mustavalkoinen"</item>
     <item msgid="2762241247228983754">"Väri"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ei mitään"</item>
+    <item msgid="7296563835355641719">"Pitkä reuna"</item>
+    <item msgid="79513688117503758">"Lyhyt reuna"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Pysty"</item>
     <item msgid="3199660090246166812">"Vaaka"</item>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 279a467..ed605e8 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Taille du papier"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Taille du papier :"</string>
     <string name="label_color" msgid="1108690305218188969">"Couleur"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Toutes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Noir et blanc"</item>
     <item msgid="2762241247228983754">"Couleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Aucune"</item>
+    <item msgid="7296563835355641719">"Bord long"</item>
+    <item msgid="79513688117503758">"Bord court"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Paysage"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index ebfd5de..a88b3f2 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Taille du papier"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Taille du papier :"</string>
     <string name="label_color" msgid="1108690305218188969">"Couleur"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Recto verso"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Toutes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Noir et blanc"</item>
     <item msgid="2762241247228983754">"Couleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Aucun"</item>
+    <item msgid="7296563835355641719">"Bord long"</item>
+    <item msgid="79513688117503758">"Bord court"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Paysage"</item>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 6e542ea..c5a271a 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Tamaño do papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño do papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Cor"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dobre cara"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páxinas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"As <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Branco e negro"</item>
     <item msgid="2762241247228983754">"Cor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ningún"</item>
+    <item msgid="7296563835355641719">"Bordo longo"</item>
+    <item msgid="79513688117503758">"Bordo curto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index a3f7fef..6bf4aa8 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"काग़ज़ का आकार"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"काग़ज़ का आकार:"</string>
     <string name="label_color" msgid="1108690305218188969">"रंग"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"डुप्‍लेक्‍स"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिविन्‍यास"</string>
     <string name="label_pages" msgid="7768589729282182230">"पृष्ठ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सभी <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"श्याम और श्वेत"</item>
     <item msgid="2762241247228983754">"रंग"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"कोई नहीं"</item>
+    <item msgid="7296563835355641719">"लंबा सिरा"</item>
+    <item msgid="79513688117503758">"छोटा सिरा"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"पोर्ट्रेट"</item>
     <item msgid="3199660090246166812">"लैंडस्केप"</item>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 8132d21..eddff9a 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Veličina papira"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Veličina papira:"</string>
     <string name="label_color" msgid="1108690305218188969">"U boji"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Obostrano"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orijentacija"</string>
     <string name="label_pages" msgid="7768589729282182230">"Stranice"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Sve stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Crno-bijelo"</item>
     <item msgid="2762241247228983754">"U boji"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ništa"</item>
+    <item msgid="7296563835355641719">"Dulji rub"</item>
+    <item msgid="79513688117503758">"Kraći rub"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Pejzaž"</item>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 3ebc450..08a36b3 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papírméret"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papírméret:"</string>
     <string name="label_color" msgid="1108690305218188969">"Szín"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Kétoldalas"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Tájolás"</string>
     <string name="label_pages" msgid="7768589729282182230">"Oldalak"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Összes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Fekete-fehér"</item>
     <item msgid="2762241247228983754">"Szín"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nincs"</item>
+    <item msgid="7296563835355641719">"Hosszabb él"</item>
+    <item msgid="79513688117503758">"Rövidebb él"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Álló"</item>
     <item msgid="3199660090246166812">"Fekvő"</item>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 5ef15a5c..5936607 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Թղթի չափը"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Թղթի չափը՝"</string>
     <string name="label_color" msgid="1108690305218188969">"Գույնը"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Երկակի"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Դիրքավորում"</string>
     <string name="label_pages" msgid="7768589729282182230">"Էջեր"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Բոլորը՝ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Սև ու սպիտակ"</item>
     <item msgid="2762241247228983754">"Գույնը"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ոչ մեկը"</item>
+    <item msgid="7296563835355641719">"Լայնեզր"</item>
+    <item msgid="79513688117503758">"Կարճեզր"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Դիմանկար"</item>
     <item msgid="3199660090246166812">"Լանդշաֆտ"</item>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 9714b0f..ab30df1 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Ukuran kertas"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Ukuran kertas:"</string>
     <string name="label_color" msgid="1108690305218188969">"Warna"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
     <string name="label_pages" msgid="7768589729282182230">"Halaman"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Semua dari <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Hitam &amp; Putih"</item>
     <item msgid="2762241247228983754">"Warna"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Tidak ada"</item>
+    <item msgid="7296563835355641719">"Tepi panjang"</item>
+    <item msgid="79513688117503758">"Tepi pendek"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Potret"</item>
     <item msgid="3199660090246166812">"Lanskap"</item>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 41a047d..c6422b1 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Pappírsstærð"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Pappírsstærð:"</string>
     <string name="label_color" msgid="1108690305218188969">"Litur"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Tvíhliða"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Stefna"</string>
     <string name="label_pages" msgid="7768589729282182230">"Síður"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Allar <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Svarthvítt"</item>
     <item msgid="2762241247228983754">"Í lit"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ekki í boði"</item>
+    <item msgid="7296563835355641719">"Langhlið"</item>
+    <item msgid="79513688117503758">"Skammhlið"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Skammsnið"</item>
     <item msgid="3199660090246166812">"Langsnið"</item>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 3653c56..9544ba7 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Dimensioni carta"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Dimensioni carta:"</string>
     <string name="label_color" msgid="1108690305218188969">"A colori"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Due tonalità (Duplex)"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientamento"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pagine"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Tutte e <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Bianco e nero"</item>
     <item msgid="2762241247228983754">"A colori"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nessuno"</item>
+    <item msgid="7296563835355641719">"Lato lungo"</item>
+    <item msgid="79513688117503758">"Lato corto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Verticale"</item>
     <item msgid="3199660090246166812">"Orizzontale"</item>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index ba293a0..e3e6123 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"גודל נייר"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"גודל נייר:"</string>
     <string name="label_color" msgid="1108690305218188969">"צבע"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"דו-צדדי"</string>
     <string name="label_orientation" msgid="2853142581990496477">"כיוון"</string>
     <string name="label_pages" msgid="7768589729282182230">"עמודים"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"הכל <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"שחור ולבן"</item>
     <item msgid="2762241247228983754">"צבע"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ללא"</item>
+    <item msgid="7296563835355641719">"צד ארוך"</item>
+    <item msgid="79513688117503758">"צד קצר"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"לאורך"</item>
     <item msgid="3199660090246166812">"לרוחב"</item>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index f3fed3b..a433d51 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"用紙サイズ"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"用紙サイズ:"</string>
     <string name="label_color" msgid="1108690305218188969">"カラー選択"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"両面印刷"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"ページ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ページすべて"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"モノクロ"</item>
     <item msgid="2762241247228983754">"カラー"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"なし"</item>
+    <item msgid="7296563835355641719">"長辺"</item>
+    <item msgid="79513688117503758">"短辺"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"縦向き"</item>
     <item msgid="3199660090246166812">"横向き"</item>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 061e9fb..6edd2f3 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"ფურცლის ზომა"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"ფურცლის ზომა:"</string>
     <string name="label_color" msgid="1108690305218188969">"ფერი"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"დუპლექსი"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ორიენტაცია"</string>
     <string name="label_pages" msgid="7768589729282182230">"გვერდები"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ყველა <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"შავ-თეთრი"</item>
     <item msgid="2762241247228983754">"ფერი"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"არც ერთი"</item>
+    <item msgid="7296563835355641719">"გრძელი კიდე"</item>
+    <item msgid="79513688117503758">"მოკლე კიდე"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"პორტრეტი"</item>
     <item msgid="3199660090246166812">"პეიზაჟის რეჟიმი"</item>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index b02714b..13dfa04 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Қағаз өлшемі"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Қағаз өлшемі:"</string>
     <string name="label_color" msgid="1108690305218188969">"Түс"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Дуплексті"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Бағыты"</string>
     <string name="label_pages" msgid="7768589729282182230">"Беттер"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Барлық <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Қара &amp; Ақ"</item>
     <item msgid="2762241247228983754">"Түс"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ешқандай"</item>
+    <item msgid="7296563835355641719">"Ұзын жиек"</item>
+    <item msgid="79513688117503758">"Қысқа жиек"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Портреттік"</item>
     <item msgid="3199660090246166812">"Ландшафт"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 63d710a..2777b7e 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"ទំហំ​​ក្រដាស"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"ទំហំ​ក្រដាស៖"</string>
     <string name="label_color" msgid="1108690305218188969">"ពណ៌"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ឌុប"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ទិស"</string>
     <string name="label_pages" msgid="7768589729282182230">"ទំព័រ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> ទាំងអស់"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ស &amp; ខ្មៅ"</item>
     <item msgid="2762241247228983754">"ពណ៌"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"គ្មាន"</item>
+    <item msgid="7296563835355641719">"គែម​វែង"</item>
+    <item msgid="79513688117503758">"គែម​ខ្លី"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"បញ្ឈរ"</item>
     <item msgid="3199660090246166812">"ផ្ដេក"</item>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index 3950866..15bc98b 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"ಪೇಪರ್ ಗಾತ್ರ"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"ಪೇಪರ್ ಗಾತ್ರ:"</string>
     <string name="label_color" msgid="1108690305218188969">"ಬಣ್ಣ"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ಡ್ಯೂಪ್ಲೆಕ್ಸ್"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ಓರಿಯಂಟೇಶನ್"</string>
     <string name="label_pages" msgid="7768589729282182230">"ಪುಟಗಳು"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ಎಲ್ಲಾ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ಕಪ್ಪು &amp; ಬಿಳುಪು"</item>
     <item msgid="2762241247228983754">"ಬಣ್ಣ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ಯಾವುದೂ ಇಲ್ಲ"</item>
+    <item msgid="7296563835355641719">"ಉದ್ದವಾದ ಅಂಚು"</item>
+    <item msgid="79513688117503758">"ಚಿಕ್ಕದಾದ ಅಂಚು"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ಪೋಟ್ರೇಟ್"</item>
     <item msgid="3199660090246166812">"ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</item>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index f1a4869..6db4cce 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"용지 크기"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"용지 크기:"</string>
     <string name="label_color" msgid="1108690305218188969">"색상"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"양면"</string>
     <string name="label_orientation" msgid="2853142581990496477">"방향"</string>
     <string name="label_pages" msgid="7768589729282182230">"페이지"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>페이지 모두"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"흑백"</item>
     <item msgid="2762241247228983754">"컬러"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"없음"</item>
+    <item msgid="7296563835355641719">"옆으로 넘김"</item>
+    <item msgid="79513688117503758">"위로 넘김"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"세로"</item>
     <item msgid="3199660090246166812">"가로"</item>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index 602f6605..6a989de 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Барактын өлчөмү"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Барактын өлчөмү:"</string>
     <string name="label_color" msgid="1108690305218188969">"Түс"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Кош тараптуу"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Багыттоо"</string>
     <string name="label_pages" msgid="7768589729282182230">"Баракчалар"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Бардыгы <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Кара-ак"</item>
     <item msgid="2762241247228983754">"Түстүү"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Эч бири"</item>
+    <item msgid="7296563835355641719">"Узун кыр"</item>
+    <item msgid="79513688117503758">"Кыска кыр"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Тикесинен"</item>
     <item msgid="3199660090246166812">"Туурасынан"</item>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 3a3f6bb..20a3d80 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"​ຂະ​ໜາດ​ເຈ້ຍ"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"​ຂະ​ໜາດ​ເຈ້ຍ:"</string>
     <string name="label_color" msgid="1108690305218188969">"ສີ"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ສອງ​ໜ້າ"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ລວງ"</string>
     <string name="label_pages" msgid="7768589729282182230">"ໜ້າ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ທັງ​ໝົດ <xliff:g id="PAGE_COUNT">%1$s</xliff:g> ໜ້າ"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ຂາວດຳ"</item>
     <item msgid="2762241247228983754">"ສີ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ບໍ່ມີ"</item>
+    <item msgid="7296563835355641719">"ຂອບຍາວ"</item>
+    <item msgid="79513688117503758">"ຂອບສັ້ນ"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ລວງຕັ້ງ"</item>
     <item msgid="3199660090246166812">"ລວງນອນ"</item>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 6262a15..7340906 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Popieriaus dydis"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Popieriaus dydis:"</string>
     <string name="label_color" msgid="1108690305218188969">"Spalva"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dvipusis"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientacija"</string>
     <string name="label_pages" msgid="7768589729282182230">"Puslapiai"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Visi <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Nespalvotas"</item>
     <item msgid="2762241247228983754">"Spalva"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nėra"</item>
+    <item msgid="7296563835355641719">"Ilgasis kraštas"</item>
+    <item msgid="79513688117503758">"Trumpasis kraštas"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stačias"</item>
     <item msgid="3199660090246166812">"Gulsčias"</item>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 3a60ee5..2fb6a1a 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papīra izmērs"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papīra izmērs:"</string>
     <string name="label_color" msgid="1108690305218188969">"Krāsa"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dubults"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Virziens"</string>
     <string name="label_pages" msgid="7768589729282182230">"Lapas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Visas <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Melnbalts"</item>
     <item msgid="2762241247228983754">"Krāsa"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nav"</item>
+    <item msgid="7296563835355641719">"Garā mala"</item>
+    <item msgid="79513688117503758">"Īsā mala"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrets"</item>
     <item msgid="3199660090246166812">"Ainava"</item>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index 91b5763..bf2e262 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Големина на хартија"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Големина на хартија:"</string>
     <string name="label_color" msgid="1108690305218188969">"Боја"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Двострано"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентација"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страници"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Сите <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Црно-бела"</item>
     <item msgid="2762241247228983754">"Во боја"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Нема"</item>
+    <item msgid="7296563835355641719">"Долг раб"</item>
+    <item msgid="79513688117503758">"Краток раб"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Портрет"</item>
     <item msgid="3199660090246166812">"Пејзаж"</item>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index a06ca7d..26d1788 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"പേപ്പർ വലുപ്പം"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"പേപ്പർ വലുപ്പം:"</string>
     <string name="label_color" msgid="1108690305218188969">"നിറം"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"രണ്ടുഭാഗങ്ങളുള്ളത്"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ഓറിയന്‍റേഷന്‍‌"</string>
     <string name="label_pages" msgid="7768589729282182230">"പേജുകൾ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"എല്ലാ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"കറുപ്പ് &amp; വെള്ള"</item>
     <item msgid="2762241247228983754">"നിറം"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ഒന്നുമില്ല"</item>
+    <item msgid="7296563835355641719">"നീളമുള്ള അരിക്"</item>
+    <item msgid="79513688117503758">"ഹ്രസ്വ അരിക്"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"പോർട്രെയ്‌റ്റ്"</item>
     <item msgid="3199660090246166812">"ലാൻഡ്‌സ്‌കേപ്പ്"</item>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 022adda..34da683 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Цаасны хэмжээ"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Цаасны хэмжээ:"</string>
     <string name="label_color" msgid="1108690305218188969">"Өнгө"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Хоёр талд нь хэвлэх"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Чиглэл"</string>
     <string name="label_pages" msgid="7768589729282182230">"Хуудас"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Нийт <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Хар &amp; Цагаан"</item>
     <item msgid="2762241247228983754">"Өнгө"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Хоосон"</item>
+    <item msgid="7296563835355641719">"Урт ирмэг"</item>
+    <item msgid="79513688117503758">"Богино ирмэг"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Босоо"</item>
     <item msgid="3199660090246166812">"Хэвтээ"</item>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index 1fade66..d2aa367 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"कागद आकार"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"कागद आकार:"</string>
     <string name="label_color" msgid="1108690305218188969">"रंग"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"डुप्लेक्स"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिमुखता"</string>
     <string name="label_pages" msgid="7768589729282182230">"पृष्ठे"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सर्व <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"कृष्‍ण धवल"</item>
     <item msgid="2762241247228983754">"रंग"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"काहीही नाही"</item>
+    <item msgid="7296563835355641719">"दीर्घ किनार"</item>
+    <item msgid="79513688117503758">"लघु किनार"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"पोट्रेट"</item>
     <item msgid="3199660090246166812">"भूदृश्य"</item>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index a392b76..6b0754c 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Saiz kertas"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Saiz kertas:"</string>
     <string name="label_color" msgid="1108690305218188969">"Warna"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
     <string name="label_pages" msgid="7768589729282182230">"Halaman"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Semua <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Hitam &amp; Putih"</item>
     <item msgid="2762241247228983754">"Warna"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Tiada"</item>
+    <item msgid="7296563835355641719">"Sisi panjang"</item>
+    <item msgid="79513688117503758">"Sisi pendek"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Potret"</item>
     <item msgid="3199660090246166812">"Landskap"</item>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index d6eb380..c87eca1 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"စက္ကူ  ဆိုက်"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"စက္ကူ  ဆိုက်:"</string>
     <string name="label_color" msgid="1108690305218188969">"ရောင်စုံ"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ဂျူးပလက်စ်"</string>
     <string name="label_orientation" msgid="2853142581990496477">"အနေအထား"</string>
     <string name="label_pages" msgid="7768589729282182230">"စာမျက်နှာများ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"အားလုံး <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"အဖြူ အမည်း"</item>
     <item msgid="2762241247228983754">"ရောင်စုံ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"မရှိ"</item>
+    <item msgid="7296563835355641719">"အနားသတ် အရှည်"</item>
+    <item msgid="79513688117503758">"အနားသတ် အတို"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ထောင်လိုက်"</item>
     <item msgid="3199660090246166812">"အလျားလိုက်"</item>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index bf11068..441444e 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papirstørrelse"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papirstørrelse:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farge"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sider"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Svart og hvitt"</item>
     <item msgid="2762241247228983754">"Farge"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ingen"</item>
+    <item msgid="7296563835355641719">"Langsiden"</item>
+    <item msgid="79513688117503758">"Kortsiden"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stående"</item>
     <item msgid="3199660090246166812">"Liggende"</item>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index eb97530..dd20bbb 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"कागजको आकार"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"कागजको आकार:"</string>
     <string name="label_color" msgid="1108690305218188969">"रङ्ग"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"डुप्लेक्स"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिमुखिकरण"</string>
     <string name="label_pages" msgid="7768589729282182230">"पृष्ठहरू"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सबै <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"कालो &amp; सेतो"</item>
     <item msgid="2762241247228983754">"रङ्ग"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"कुनै पनि होइन"</item>
+    <item msgid="7296563835355641719">"लामो किनारा"</item>
+    <item msgid="79513688117503758">"छोटो किनारा"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"पोट्रेट"</item>
     <item msgid="3199660090246166812">"परिदृश्य"</item>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 5ea52a0..31c0110 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Papierformaat"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Papierformaat:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kleur"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Stand"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pagina\'s"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Zwart-wit"</item>
     <item msgid="2762241247228983754">"Kleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Geen"</item>
+    <item msgid="7296563835355641719">"Lange zijde"</item>
+    <item msgid="79513688117503758">"Korte zijde"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Landschap"</item>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 609e6e9..ccba0d5 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Rozmiar papieru"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Rozmiar papieru:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kolor"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientacja"</string>
     <string name="label_pages" msgid="7768589729282182230">"Strony"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Wszystkie <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Czarno-białe"</item>
     <item msgid="2762241247228983754">"Kolor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Brak"</item>
+    <item msgid="7296563835355641719">"Długa krawędź"</item>
+    <item msgid="79513688117503758">"Krótka krawędź"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Pionowa"</item>
     <item msgid="3199660090246166812">"Pozioma"</item>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 7b47f4c..5efa1d7 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Tamanho do papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamanho do papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Cor"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Frente e verso"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas as <xliff:g id="PAGE_COUNT">%1$s</xliff:g> páginas"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Preto e branco"</item>
     <item msgid="2762241247228983754">"Cor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nenhum"</item>
+    <item msgid="7296563835355641719">"Limite grande"</item>
+    <item msgid="79513688117503758">"Limite curto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 3038a7f..52875dd 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Tamanho do papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamanho do papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Cor"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas as <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Preto e branco"</item>
     <item msgid="2762241247228983754">"Cor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nenhum"</item>
+    <item msgid="7296563835355641719">"Borda longa"</item>
+    <item msgid="79513688117503758">"Borda curta"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Retrato"</item>
     <item msgid="3199660090246166812">"Paisagem"</item>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 1446a53..98d3761 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Formatul hârtiei"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Formatul hârtiei:"</string>
     <string name="label_color" msgid="1108690305218188969">"Color"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientare"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pagini"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Toate cele <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Alb-negru"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Fără"</item>
+    <item msgid="7296563835355641719">"Latura lungă"</item>
+    <item msgid="79513688117503758">"Latura scurtă"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Peisaj"</item>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index c2a19bb..4d9861a 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Размер бумаги"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер бумаги:"</string>
     <string name="label_color" msgid="1108690305218188969">"Печать"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Двусторонняя печать"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страницы"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Все <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Черно-белая"</item>
     <item msgid="2762241247228983754">"Цветная"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Нет"</item>
+    <item msgid="7296563835355641719">"Длинный край"</item>
+    <item msgid="79513688117503758">"Короткий край"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Книга"</item>
     <item msgid="3199660090246166812">"Альбом"</item>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 386ce8d..dae8a02 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"කඩදාසියේ ප්‍රමාණය"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"කඩදාසියේ ප්‍රමාණය:"</string>
     <string name="label_color" msgid="1108690305218188969">"වර්ණය"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ඩුප්ලෙක්ස්"</string>
     <string name="label_orientation" msgid="2853142581990496477">"දිශානතිය"</string>
     <string name="label_pages" msgid="7768589729282182230">"පිටු"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"සියලුම <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"කළු සහ සුදු"</item>
     <item msgid="2762241247228983754">"වර්ණය"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"කිසිවක් නැත"</item>
+    <item msgid="7296563835355641719">"දිගු දාරය"</item>
+    <item msgid="79513688117503758">"කෙටි දාරය"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ප්‍රතිමුර්ති"</item>
     <item msgid="3199660090246166812">"තිරස් දර්ශනය"</item>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 5be2034..ecb70b8 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Veľkosť papiera"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Veľkosť papiera:"</string>
     <string name="label_color" msgid="1108690305218188969">"Farba"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientácia"</string>
     <string name="label_pages" msgid="7768589729282182230">"Strany"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Všetky: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Čiernobiele"</item>
     <item msgid="2762241247228983754">"Farba"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Žiadne"</item>
+    <item msgid="7296563835355641719">"Dlhý okraj"</item>
+    <item msgid="79513688117503758">"Krátky okraj"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Na výšku"</item>
     <item msgid="3199660090246166812">"Na šírku"</item>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index ee15103..c94429e 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Velikost papirja"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Velikost papirja:"</string>
     <string name="label_color" msgid="1108690305218188969">"Barvno"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Obojestransko"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Postavitev"</string>
     <string name="label_pages" msgid="7768589729282182230">"Strani"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Vse (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Črno-belo"</item>
     <item msgid="2762241247228983754">"Barvno"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Brez"</item>
+    <item msgid="7296563835355641719">"Dolgi rob"</item>
+    <item msgid="79513688117503758">"Kratki rob"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Pokončno"</item>
     <item msgid="3199660090246166812">"Ležeče"</item>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 6ca94aa..7bc912c 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Величина папира"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Величина папира:"</string>
     <string name="label_color" msgid="1108690305218188969">"Боја"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Обострани режим"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Положај"</string>
     <string name="label_pages" msgid="7768589729282182230">"Странице"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Све странице (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Црно-бело"</item>
     <item msgid="2762241247228983754">"Боја"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ништа"</item>
+    <item msgid="7296563835355641719">"Дуга ивица"</item>
+    <item msgid="79513688117503758">"Кратка ивица"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Усправно"</item>
     <item msgid="3199660090246166812">"Водоравно"</item>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 4c439be..c46d4df 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Pappersstorlek"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Pappersstorlek:"</string>
     <string name="label_color" msgid="1108690305218188969">"Färg"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dubbelsidigt"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientering"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sidor"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alla <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Svartvit"</item>
     <item msgid="2762241247228983754">"Färg"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ingen"</item>
+    <item msgid="7296563835355641719">"Långsidan"</item>
+    <item msgid="79513688117503758">"Kortsidan"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stående"</item>
     <item msgid="3199660090246166812">"Liggande"</item>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index e454704..9c808be 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Ukubwa wa karatasi"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Ukubwa wa karatasi:"</string>
     <string name="label_color" msgid="1108690305218188969">"Rangi"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Maradufu"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Mkao"</string>
     <string name="label_pages" msgid="7768589729282182230">"Kurasa"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Kurasa zote <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Nyeusi na Nyeupe"</item>
     <item msgid="2762241247228983754">"Rangi"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Hamna"</item>
+    <item msgid="7296563835355641719">"Ukingo mrefu"</item>
+    <item msgid="79513688117503758">"Ukingo mfupi"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Wima"</item>
     <item msgid="3199660090246166812">"Mlalo"</item>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index 0421bd6..1395d29 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"காகித அளவு"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"காகித அளவு:"</string>
     <string name="label_color" msgid="1108690305218188969">"வண்ணம்"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"டியூப்ளெக்ஸ்"</string>
     <string name="label_orientation" msgid="2853142581990496477">"திசையமைப்பு"</string>
     <string name="label_pages" msgid="7768589729282182230">"பக்கங்கள்"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"எல்லாம்: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"கருப்பு &amp; வெள்ளை"</item>
     <item msgid="2762241247228983754">"வண்ணம்"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ஏதுமில்லை"</item>
+    <item msgid="7296563835355641719">"லாங் எட்ஜ்"</item>
+    <item msgid="79513688117503758">"ஷார்ட் எட்ஜ்"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"உறுவப்படம்"</item>
     <item msgid="3199660090246166812">"நிலத்தோற்றம்"</item>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index edb6e60..9958f05 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"కాగితపు పరిమాణం"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"కాగితపు పరిమాణం:"</string>
     <string name="label_color" msgid="1108690305218188969">"రంగు"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"డూప్లెక్స్"</string>
     <string name="label_orientation" msgid="2853142581990496477">"దృగ్విన్యాసం"</string>
     <string name="label_pages" msgid="7768589729282182230">"పేజీలు"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"మొత్తం <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"నలుపు &amp; తెలుపు"</item>
     <item msgid="2762241247228983754">"రంగు"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ఏదీ వద్దు"</item>
+    <item msgid="7296563835355641719">"పొడవైన అంచు"</item>
+    <item msgid="79513688117503758">"చిన్న అంచు"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"పోర్ట్రెయిట్"</item>
     <item msgid="3199660090246166812">"ల్యాండ్‌స్కేప్"</item>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index cfffa0b..cef716a 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"ขนาดของกระดาษ"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"ขนาดของกระดาษ:"</string>
     <string name="label_color" msgid="1108690305218188969">"สี"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ดูเพล็กซ์"</string>
     <string name="label_orientation" msgid="2853142581990496477">"การวางแนว"</string>
     <string name="label_pages" msgid="7768589729282182230">"หน้า"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ทั้ง <xliff:g id="PAGE_COUNT">%1$s</xliff:g> หน้า"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ขาวดำ"</item>
     <item msgid="2762241247228983754">"สี"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ไม่มี"</item>
+    <item msgid="7296563835355641719">"ขอบยาว"</item>
+    <item msgid="79513688117503758">"ขอบสั้น"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"แนวตั้ง"</item>
     <item msgid="3199660090246166812">"แนวนอน"</item>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index dfb0450..58e1930 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Laki ng papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Laki ng papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Kulay"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Oryentasyon"</string>
     <string name="label_pages" msgid="7768589729282182230">"Mga Page"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Lahat ng <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Black &amp; White"</item>
     <item msgid="2762241247228983754">"Kulay"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Wala"</item>
+    <item msgid="7296563835355641719">"Long edge"</item>
+    <item msgid="79513688117503758">"Short edge"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Landscape"</item>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index 50befba..39b5c9a 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Kağıt boyutu"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Kağıt boyutu:"</string>
     <string name="label_color" msgid="1108690305218188969">"Renkli"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dubleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Sayfa yönü"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sayfa"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> sayfanın tamamı"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Siyah Beyaz"</item>
     <item msgid="2762241247228983754">"Renkli"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Yok"</item>
+    <item msgid="7296563835355641719">"Uzun kenar"</item>
+    <item msgid="79513688117503758">"Kısa kenar"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Dikey"</item>
     <item msgid="3199660090246166812">"Yatay"</item>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 8a924e6..73030e4 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Розмір паперу"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Розмір паперу:"</string>
     <string name="label_color" msgid="1108690305218188969">"Колір"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Двосторонній друк"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Орієнтація"</string>
     <string name="label_pages" msgid="7768589729282182230">"Сторінки"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Усі <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Чорно-білий"</item>
     <item msgid="2762241247228983754">"Колір"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Немає"</item>
+    <item msgid="7296563835355641719">"Довгий край"</item>
+    <item msgid="79513688117503758">"Короткий край"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Книжкова"</item>
     <item msgid="3199660090246166812">"Альбомна"</item>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index 722d027..5c9f471 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"کاغذ کا سائز"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"کاغذ کا سائز:"</string>
     <string name="label_color" msgid="1108690305218188969">"رنگ"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"ڈوپلیکس"</string>
     <string name="label_orientation" msgid="2853142581990496477">"سمت بندی"</string>
     <string name="label_pages" msgid="7768589729282182230">"صفحات"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"سبھی <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"سیاہ و سفید"</item>
     <item msgid="2762241247228983754">"رنگ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"کوئی نہیں"</item>
+    <item msgid="7296563835355641719">"طویل کنارہ"</item>
+    <item msgid="79513688117503758">"مختصر کنارہ"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"پورٹریٹ"</item>
     <item msgid="3199660090246166812">"لینڈ اسکیپ"</item>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index f62728f..40b7109 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Qog‘oz o‘lchami"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Qog‘oz o‘lchami:"</string>
     <string name="label_color" msgid="1108690305218188969">"Rang"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Ikki tomonlama"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Joylashuv"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sahifalar"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Barchasi (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Oq &amp; qora"</item>
     <item msgid="2762241247228983754">"Rang"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Hech biri"</item>
+    <item msgid="7296563835355641719">"Uzun tomoni"</item>
+    <item msgid="79513688117503758">"Qisqa tomoni"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Bo‘yiga"</item>
     <item msgid="3199660090246166812">"Eniga"</item>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index fa0d26e..c61c1fa 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Khổ giấy"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Khổ giấy:"</string>
     <string name="label_color" msgid="1108690305218188969">"Màu"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Hai mặt"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Hướng"</string>
     <string name="label_pages" msgid="7768589729282182230">"Trang"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Tất cả <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Đen trắng"</item>
     <item msgid="2762241247228983754">"Màu"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Không có"</item>
+    <item msgid="7296563835355641719">"Cạnh dài"</item>
+    <item msgid="79513688117503758">"Cạnh ngắn"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Dọc"</item>
     <item msgid="3199660090246166812">"Ngang"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 77ecb21..3eb1b63 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"纸张尺寸"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"纸张尺寸:"</string>
     <string name="label_color" msgid="1108690305218188969">"颜色"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"双面模式"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"页数"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"全部<xliff:g id="PAGE_COUNT">%1$s</xliff:g>页"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"黑白"</item>
     <item msgid="2762241247228983754">"彩色"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"无"</item>
+    <item msgid="7296563835355641719">"长边"</item>
+    <item msgid="79513688117503758">"短边"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"纵向"</item>
     <item msgid="3199660090246166812">"横向"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index d2fa629..88c6961 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"紙張大小"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"紙張大小:"</string>
     <string name="label_color" msgid="1108690305218188969">"顏色"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"雙面列印"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"頁數"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"全部 <xliff:g id="PAGE_COUNT">%1$s</xliff:g> 頁"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"黑白"</item>
     <item msgid="2762241247228983754">"彩色"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"無"</item>
+    <item msgid="7296563835355641719">"長邊"</item>
+    <item msgid="79513688117503758">"短邊"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"直向"</item>
     <item msgid="3199660090246166812">"橫向"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 3e26a5e..2d8631c 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"紙張大小"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"紙張大小:"</string>
     <string name="label_color" msgid="1108690305218188969">"色彩"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"雙面"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"頁面"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"全部 <xliff:g id="PAGE_COUNT">%1$s</xliff:g> 頁"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"黑白"</item>
     <item msgid="2762241247228983754">"彩色"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"無"</item>
+    <item msgid="7296563835355641719">"長邊"</item>
+    <item msgid="79513688117503758">"短邊"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"縱向"</item>
     <item msgid="3199660090246166812">"橫向"</item>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index f8a27bc..d3ee17c 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Usayizi wekhasi"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Usayizi wekhasi"</string>
     <string name="label_color" msgid="1108690305218188969">"Umbala"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Umumo"</string>
     <string name="label_pages" msgid="7768589729282182230">"Amakhasi"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Konke <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Okumnyama nokumhlophe"</item>
     <item msgid="2762241247228983754">"Umbala"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Lutho"</item>
+    <item msgid="7296563835355641719">"Emaphethelweni amade"</item>
+    <item msgid="79513688117503758">"Emaphethelweni amafushane"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Ukuma ngobude"</item>
     <item msgid="3199660090246166812">"Ukwakheka kwezwe"</item>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index ab633ea..9d67ccc 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -40,6 +40,9 @@
     <!-- Label of the color mode widget. [CHAR LIMIT=20] -->
     <string name="label_color">Color</string>
 
+    <!-- Label of the duplex mode widget. [CHAR LIMIT=20] -->
+    <string name="label_duplex">Duplex</string>
+
     <!-- Label of the orientation widget. [CHAR LIMIT=20] -->
     <string name="label_orientation">Orientation</string>
 
@@ -188,12 +191,22 @@
 
     <!-- Color mode labels. -->
     <string-array name="color_mode_labels">
-        <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
+        <!-- Color mode label: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
         <item>Black &amp; White</item>
         <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] -->
         <item>Color</item>
     </string-array>
 
+    <!-- Duplex mode labels. -->
+    <string-array name="duplex_mode_labels">
+        <!-- Duplex mode label: No duplex supported. [CHAR LIMIT=20] -->
+        <item>None</item>
+        <!-- Duplex mode label: Turn page sideways along the long edge like a book. [CHAR LIMIT=20] -->
+        <item>Long edge</item>
+        <!-- Duplex mode label: Turn page upwards along the short edge like a notepad. [CHAR LIMIT=20] -->
+        <item>Short edge</item>
+    </string-array>
+
     <!-- Orientation labels. -->
     <string-array name="orientation_labels">
         <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 2cc5e04..377d2d5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -695,6 +695,7 @@
         private static final String TAG_MARGINS = "margins";
 
         private static final String ATTR_COLOR_MODE = "colorMode";
+        private static final String ATTR_DUPLEX_MODE = "duplexMode";
 
         private static final String ATTR_LOCAL_ID = "localId";
         private static final String ATTR_SERVICE_NAME = "serviceName";
@@ -823,6 +824,10 @@
                         serializer.attribute(null, ATTR_COLOR_MODE,
                                 String.valueOf(colorMode));
 
+                        final int duplexMode = attributes.getDuplexMode();
+                        serializer.attribute(null, ATTR_DUPLEX_MODE,
+                                String.valueOf(duplexMode));
+
                         MediaSize mediaSize = attributes.getMediaSize();
                         if (mediaSize != null) {
                             serializer.startTag(null, TAG_MEDIA_SIZE);
@@ -1057,6 +1062,12 @@
                 String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
                 builder.setColorMode(Integer.parseInt(colorMode));
 
+                String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE);
+                // Duplex mode was added later, so null check is needed.
+                if (duplexMode != null) {
+                    builder.setDuplexMode(Integer.parseInt(duplexMode));
+                }
+
                 parser.next();
 
                 skipEmptyTextTags(parser);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f3a5c95..4ba04e5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -184,6 +184,9 @@
     private Spinner mColorModeSpinner;
     private ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
 
+    private Spinner mDuplexModeSpinner;
+    private ArrayAdapter<SpinnerItem<Integer>> mDuplexModeSpinnerAdapter;
+
     private Spinner mOrientationSpinner;
     private ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
 
@@ -767,6 +770,21 @@
                     }
                 }
             }
+
+            // Take the duplex mode only if the current printer supports it.
+            final int currDuplexMode = currAttributes.getDuplexMode();
+            final int newDuplexMode = newAttributes.getDuplexMode();
+            if (currDuplexMode != newDuplexMode) {
+                final int duplexModeCount = mDuplexModeSpinner.getCount();
+                for (int i = 0; i < duplexModeCount; i++) {
+                    final int supportedDuplexMode = mDuplexModeSpinnerAdapter.getItem(i).value;
+                    if (supportedDuplexMode == newDuplexMode) {
+                        currAttributes.setDuplexMode(newDuplexMode);
+                        mDuplexModeSpinner.setSelection(i);
+                        break;
+                    }
+                }
+            }
         }
 
         // Handle selected page changes making sure they are in the doc.
@@ -985,6 +1003,12 @@
             attributes.setColorMode(defaults.getColorMode());
         }
 
+        // Duplex mode.
+        final int duplexMode = attributes.getDuplexMode();
+        if ((capabilities.getDuplexModes() & duplexMode) == 0) {
+            attributes.setDuplexMode(defaults.getDuplexMode());
+        }
+
         // Resolution
         Resolution resolution = attributes.getResolution();
         if (resolution == null || !capabilities.getResolutions().contains(resolution)) {
@@ -1111,6 +1135,13 @@
         mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
         mColorModeSpinner.setOnItemSelectedListener(itemSelectedListener);
 
+        // Duplex mode.
+        mDuplexModeSpinnerAdapter = new ArrayAdapter<>(
+                this, android.R.layout.simple_spinner_dropdown_item, android.R.id.text1);
+        mDuplexModeSpinner = (Spinner) findViewById(R.id.duplex_spinner);
+        mDuplexModeSpinner.setAdapter(mDuplexModeSpinnerAdapter);
+        mDuplexModeSpinner.setOnItemSelectedListener(itemSelectedListener);
+
         // Orientation
         mOrientationSpinnerAdapter = new ArrayAdapter<>(
                 this, android.R.layout.simple_spinner_dropdown_item, android.R.id.text1);
@@ -1187,6 +1218,7 @@
             mCopiesEditText.setFocusable(false);
             mMediaSizeSpinner.setEnabled(false);
             mColorModeSpinner.setEnabled(false);
+            mDuplexModeSpinner.setEnabled(false);
             mOrientationSpinner.setEnabled(false);
             mRangeOptionsSpinner.setEnabled(false);
             mPageRangeEditText.setEnabled(false);
@@ -1202,6 +1234,7 @@
             mCopiesEditText.setFocusable(false);
             mMediaSizeSpinner.setEnabled(false);
             mColorModeSpinner.setEnabled(false);
+            mDuplexModeSpinner.setEnabled(false);
             mOrientationSpinner.setEnabled(false);
             mRangeOptionsSpinner.setEnabled(false);
             mPageRangeEditText.setEnabled(false);
@@ -1317,7 +1350,7 @@
                 final int colorMode = 1 << colorBitOffset;
                 if (colorMode == oldColorMode) {
                     // Update the index of the old selection.
-                    oldColorModeNewIndex = colorBitOffset;
+                    oldColorModeNewIndex = mColorModeSpinnerAdapter.getCount();
                 }
                 remainingColorModes &= ~colorMode;
                 mColorModeSpinnerAdapter.add(new SpinnerItem<>(colorMode,
@@ -1339,11 +1372,81 @@
                             mColorModeSpinner.setSelection(i);
                         }
                         attributes.setColorMode(selectedColorMode);
+                        break;
                     }
                 }
             }
         }
 
+        // Duplex mode.
+        mDuplexModeSpinner.setEnabled(true);
+        final int duplexModes = capabilities.getDuplexModes();
+
+        // If the duplex modes changed, we update the adapter and the spinner.
+        // Note that we use bit count +1 to account for the no duplex option.
+        boolean duplexModesChanged = false;
+        if (Integer.bitCount(duplexModes) != mDuplexModeSpinnerAdapter.getCount()) {
+            duplexModesChanged = true;
+        } else {
+            int remainingDuplexModes = duplexModes;
+            int adapterIndex = 0;
+            while (remainingDuplexModes != 0) {
+                final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes);
+                final int duplexMode = 1 << duplexBitOffset;
+                remainingDuplexModes &= ~duplexMode;
+                if (duplexMode != mDuplexModeSpinnerAdapter.getItem(adapterIndex).value) {
+                    duplexModesChanged = true;
+                    break;
+                }
+                adapterIndex++;
+            }
+        }
+        if (duplexModesChanged) {
+            // Remember the old duplex mode to try selecting it again. Also the fallback
+            // is no duplexing which is always the first item in the dropdown.
+            int oldDuplexModeNewIndex = AdapterView.INVALID_POSITION;
+            final int oldDuplexMode = attributes.getDuplexMode();
+
+            // Rebuild the adapter data.
+            mDuplexModeSpinnerAdapter.clear();
+            String[] duplexModeLabels = getResources().getStringArray(R.array.duplex_mode_labels);
+            int remainingDuplexModes = duplexModes;
+            while (remainingDuplexModes != 0) {
+                final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes);
+                final int duplexMode = 1 << duplexBitOffset;
+                if (duplexMode == oldDuplexMode) {
+                    // Update the index of the old selection.
+                    oldDuplexModeNewIndex = mDuplexModeSpinnerAdapter.getCount();
+                }
+                remainingDuplexModes &= ~duplexMode;
+                mDuplexModeSpinnerAdapter.add(new SpinnerItem<>(duplexMode,
+                        duplexModeLabels[duplexBitOffset]));
+            }
+
+            if (oldDuplexModeNewIndex != AdapterView.INVALID_POSITION) {
+                // Select the old duplex mode - nothing really changed.
+                if (mDuplexModeSpinner.getSelectedItemPosition() != oldDuplexModeNewIndex) {
+                    mDuplexModeSpinner.setSelection(oldDuplexModeNewIndex);
+                }
+            } else {
+                // Select the default.
+                final int selectedDuplexMode = defaultAttributes.getDuplexMode();
+                final int itemCount = mDuplexModeSpinnerAdapter.getCount();
+                for (int i = 0; i < itemCount; i++) {
+                    SpinnerItem<Integer> item = mDuplexModeSpinnerAdapter.getItem(i);
+                    if (selectedDuplexMode == item.value) {
+                        if (mDuplexModeSpinner.getSelectedItemPosition() != i) {
+                            mDuplexModeSpinner.setSelection(i);
+                        }
+                        attributes.setDuplexMode(selectedDuplexMode);
+                        break;
+                    }
+                }
+            }
+        }
+
+        mDuplexModeSpinner.setEnabled(mDuplexModeSpinnerAdapter.getCount() > 1);
+
         // Orientation
         mOrientationSpinner.setEnabled(true);
         MediaSize mediaSize = attributes.getMediaSize();
@@ -2173,6 +2276,9 @@
             } else if (spinner == mColorModeSpinner) {
                 SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position);
                 mPrintJob.getAttributes().setColorMode(colorModeItem.value);
+            } else if (spinner == mDuplexModeSpinner) {
+                SpinnerItem<Integer> duplexModeItem = mDuplexModeSpinnerAdapter.getItem(position);
+                mPrintJob.getAttributes().setDuplexMode(duplexModeItem.value);
             } else if (spinner == mOrientationSpinner) {
                 SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java
index feb0316..6a6f1d3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java
@@ -48,16 +48,19 @@
     }
 
     @Override
+    public CharSequence getAccessibilityClassName() {
+        return CompoundButton.class.getName();
+    }
+
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        event.setClassName(CompoundButton.class.getName());
         event.setChecked(isSelected());
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(CompoundButton.class.getName());
         info.setSelected(false);
         info.setCheckable(true);
         info.setChecked(isSelected());
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
new file mode 100644
index 0000000..0245ed3
--- /dev/null
+++ b/packages/SettingsLib/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SettingsLib
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/core/res/res/color/btn_material_accent.xml b/packages/SettingsLib/AndroidManifest.xml
similarity index 64%
copy from core/res/res/color/btn_material_accent.xml
copy to packages/SettingsLib/AndroidManifest.xml
index 71469b6..eacafd5 100644
--- a/core/res/res/color/btn_material_accent.xml
+++ b/packages/SettingsLib/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+     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.
@@ -14,9 +15,6 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?attr/disabledAlpha"
-          android:color="@color/button_material_dark" />
-    <item android:color="?attr/colorAccent" />
-</selector>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.settingslib">
+</manifest>
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
new file mode 100644
index 0000000..b017047
--- /dev/null
+++ b/packages/SettingsLib/common.mk
@@ -0,0 +1,18 @@
+#
+# Include this make file to build your application against this module.
+#
+# Make sure to include it after you've set all your desired LOCAL variables.
+# Note that you must explicitly set your LOCAL_RESOURCE_DIR before including
+# this file.
+#
+# For example:
+#
+#   LOCAL_RESOURCE_DIR := \
+#        $(LOCAL_PATH)/res
+#
+#   include frameworks/base/packages/SettingsLib/common.mk
+#
+
+LOCAL_RESOURCE_DIR += $(call my-dir)/res
+LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.settingslib
+LOCAL_STATIC_JAVA_LIBRARIES += SettingsLib
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
new file mode 100644
index 0000000..a52ed69
--- /dev/null
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -0,0 +1,81 @@
+<?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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Wi-Fi settings -->
+
+    <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
+    <!-- Wi-Fi settings. The status messages when the network is unknown. -->
+    <string-array name="wifi_status">
+        <!-- Status message of Wi-Fi when it is idle. -->
+        <item></item>
+        <!-- Status message of Wi-Fi when it is scanning. -->
+        <item>Scanning\u2026</item>
+        <!-- Status message of Wi-Fi when it is connecting. -->
+        <item>Connecting\u2026</item>
+        <!-- Status message of Wi-Fi when it is authenticating. -->
+        <item>Authenticating\u2026</item>
+        <!-- Status message of Wi-Fi when it is obtaining IP address. -->
+        <item>Obtaining IP address\u2026</item>
+        <!-- Status message of Wi-Fi when it is connected. -->
+        <item>Connected</item>
+        <!-- Status message of Wi-Fi when it is suspended. -->
+        <item>Suspended</item>
+        <!-- Status message of Wi-Fi when it is disconnecting. -->
+        <item>Disconnecting\u2026</item>
+        <!-- Status message of Wi-Fi when it is disconnected. -->
+        <item>Disconnected</item>
+        <!-- Status message of Wi-Fi when it is a failure. -->
+        <item>Unsuccessful</item>
+        <!-- Status message of Wi-Fi when it is blocked. -->
+        <item>Blocked</item>
+        <!-- Status message of Wi-Fi when connectiong is being verified. -->
+        <item>Temporarily avoiding poor connection</item>
+    </string-array>
+
+    <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
+    <!-- Wi-Fi settings. The status messages when the network is known. -->
+    <string-array name="wifi_status_with_ssid">
+        <!-- Status message of Wi-Fi when it is idle. -->
+        <item></item>
+        <!-- Status message of Wi-Fi when it is scanning. -->
+        <item>Scanning\u2026</item>
+        <!-- Status message of Wi-Fi when it is connecting to a network. -->
+        <item>Connecting to <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is authenticating with a network. -->
+        <item>Authenticating with <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is obtaining IP address from a network. -->
+        <item>Obtaining IP address from <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is connected to a network. -->
+        <item>Connected to <xliff:g id="network_name">%1$s</xliff:g></item>
+        <!-- Status message of Wi-Fi when it is suspended. -->
+        <item>Suspended</item>
+        <!-- Status message of Wi-Fi when it is disconnecting from a network. -->
+        <item>Disconnecting from <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is disconnected. -->
+        <item>Disconnected</item>
+        <!-- Status message of Wi-Fi when it is a failure. -->
+        <item>Unsuccessful</item>
+        <!-- Status message of Wi-Fi when it is blocked. -->
+        <item>Blocked</item>
+        <!-- Status message of Wi-Fi when connectiong is being verified. -->
+        <item>Temporarily avoiding poor connection</item>
+    </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
new file mode 100644
index 0000000..f055a2c
--- /dev/null
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -0,0 +1,70 @@
+<?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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Toast message when Wi-Fi cannot scan for networks -->
+    <string name="wifi_fail_to_scan">Can\'t scan for networks</string>
+    <!-- Do not translate.  Concise terminology for wifi with WEP security -->
+    <string name="wifi_security_short_wep">WEP</string>
+    <!-- Do not translate.  Concise terminology for wifi with WPA security -->
+    <string name="wifi_security_short_wpa">WPA</string>
+    <!-- Do not translate.  Concise terminology for wifi with WPA2 security -->
+    <string name="wifi_security_short_wpa2">WPA2</string>
+    <!-- Do not translate.  Concise terminology for wifi with both WPA/WPA2 security -->
+    <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
+    <!-- Do not translate.  Concise terminology for wifi with unknown PSK type -->
+    <string name="wifi_security_short_psk_generic">@string/wifi_security_short_wpa_wpa2</string>
+    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
+    <string name="wifi_security_short_eap">802.1x</string>
+
+    <!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. -->
+    <string name="wifi_security_none">None</string>
+
+    <!-- Do not translate.  Terminology for wifi with WEP security -->
+    <string name="wifi_security_wep">WEP</string>
+    <!-- Do not translate.  Terminology for wifi with WPA security -->
+    <string name="wifi_security_wpa">WPA PSK</string>
+    <!-- Do not translate.  Terminology for wifi with WPA2 security -->
+    <string name="wifi_security_wpa2">WPA2 PSK</string>
+    <!-- Do not translate.  Terminology for wifi with both WPA/WPA2 security, or unknown -->
+    <string name="wifi_security_wpa_wpa2">WPA/WPA2 PSK</string>
+    <!-- Do not translate.  Terminology for wifi with unknown PSK type -->
+    <string name="wifi_security_psk_generic">@string/wifi_security_wpa_wpa2</string>
+    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
+    <string name="wifi_security_eap">802.1x EAP</string>
+
+    <!-- Summary for the remembered network. -->
+    <string name="wifi_remembered">Saved</string>
+    <!-- Status for networks disabled for unknown reason -->
+    <string name="wifi_disabled_generic">Disabled</string>
+    <!-- Status for networked disabled from a DNS or DHCP failure -->
+    <string name="wifi_disabled_network_failure">IP Configuration Failure</string>
+    <!-- Status for networked disabled from a wifi association failure -->
+    <string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
+    <!-- Status for networks disabled from authentication failure (wrong password
+         or certificate). -->
+    <string name="wifi_disabled_password_failure">Authentication problem</string>
+    <!-- Summary for the remembered network but currently not in range. -->
+    <string name="wifi_not_in_range">Not in range</string>
+    <!-- Summary for the remembered network but no internet connection was detected. -->
+    <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string>
+
+    <!-- Status message of Wi-Fi when it is connected by a Wi-Fi assistant application. [CHAR LIMIT=NONE] -->
+    <string name="connected_via_wfa">Connected via Wi\u2011Fi assistant</string>
+</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/WirelessUtils.java b/packages/SettingsLib/src/com/android/settingslib/WirelessUtils.java
new file mode 100644
index 0000000..0346a77
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/WirelessUtils.java
@@ -0,0 +1,37 @@
+/*
+ * 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.settingslib;
+
+import android.content.Context;
+import android.provider.Settings;
+
+public class WirelessUtils {
+
+    public static boolean isRadioAllowed(Context context, String type) {
+        if (!isAirplaneModeOn(context)) {
+            return true;
+        }
+        String toggleable = Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        return toggleable != null && toggleable.contains(type);
+    }
+
+    public static boolean isAirplaneModeOn(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
new file mode 100644
index 0000000..e8ab220
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -0,0 +1,739 @@
+/*
+ * 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.settingslib.wifi;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkInfo.State;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.LruCache;
+
+import com.android.settingslib.R;
+
+import java.util.Map;
+
+
+public class AccessPoint implements Comparable<AccessPoint> {
+    static final String TAG = "SettingsLib.AccessPoint";
+
+    /**
+     * Lower bound on the 2.4 GHz (802.11b/g/n) WLAN channels
+     */
+    public static final int LOWER_FREQ_24GHZ = 2400;
+
+    /**
+     * Upper bound on the 2.4 GHz (802.11b/g/n) WLAN channels
+     */
+    public static final int HIGHER_FREQ_24GHZ = 2500;
+
+    /**
+     * Lower bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
+     */
+    public static final int LOWER_FREQ_5GHZ = 4900;
+
+    /**
+     * Upper bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
+     */
+    public static final int HIGHER_FREQ_5GHZ = 5900;
+
+
+    /**
+     * Experimental: we should be able to show the user the list of BSSIDs and bands
+     *  for that SSID.
+     *  For now this data is used only with Verbose Logging so as to show the band and number
+     *  of BSSIDs on which that network is seen.
+     */
+    public LruCache<String, ScanResult> mScanResultCache;
+    private static final String KEY_NETWORKINFO = "key_networkinfo";
+    private static final String KEY_WIFIINFO = "key_wifiinfo";
+    private static final String KEY_SCANRESULT = "key_scanresult";
+    private static final String KEY_CONFIG = "key_config";
+
+    /**
+     * These values are matched in string arrays -- changes must be kept in sync
+     */
+    public static final int SECURITY_NONE = 0;
+    public static final int SECURITY_WEP = 1;
+    public static final int SECURITY_PSK = 2;
+    public static final int SECURITY_EAP = 3;
+
+    private static final int PSK_UNKNOWN = 0;
+    private static final int PSK_WPA = 1;
+    private static final int PSK_WPA2 = 2;
+    private static final int PSK_WPA_WPA2 = 3;
+
+    private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
+    private final Context mContext;
+
+    private String ssid;
+    private int security;
+    private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
+
+    private int pskType = PSK_UNKNOWN;
+
+    private WifiConfiguration mConfig;
+    private ScanResult mScanResult;
+
+    private int mRssi = Integer.MAX_VALUE;
+    private long mSeen = 0;
+
+    private WifiInfo mInfo;
+    private NetworkInfo mNetworkInfo;
+    private AccessPointListener mAccessPointListener;
+
+    private Object mTag;
+
+    public AccessPoint(Context context, Bundle savedState) {
+        mContext = context;
+        mConfig = savedState.getParcelable(KEY_CONFIG);
+        if (mConfig != null) {
+            loadConfig(mConfig);
+        }
+        mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);
+        if (mScanResult != null) {
+            loadResult(mScanResult);
+        }
+        mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);
+        if (savedState.containsKey(KEY_NETWORKINFO)) {
+            mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO);
+        }
+        update(mInfo, mNetworkInfo);
+    }
+
+    AccessPoint(Context context, ScanResult result) {
+        mContext = context;
+        loadResult(result);
+    }
+
+    AccessPoint(Context context, WifiConfiguration config) {
+        mContext = context;
+        loadConfig(config);
+    }
+
+    @Override
+    public int compareTo(AccessPoint other) {
+        // Active one goes first.
+        if (isActive() && !other.isActive()) return -1;
+        if (!isActive() && other.isActive()) return 1;
+
+        // Reachable one goes before unreachable one.
+        if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
+        if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
+
+        // Configured one goes before unconfigured one.
+        if (networkId != WifiConfiguration.INVALID_NETWORK_ID
+                && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
+        if (networkId == WifiConfiguration.INVALID_NETWORK_ID
+                && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
+
+        // Sort by signal strength.
+        int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
+        if (difference != 0) {
+            return difference;
+        }
+        // Sort by ssid.
+        return ssid.compareToIgnoreCase(other.ssid);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof AccessPoint)) return false;
+        return (this.compareTo((AccessPoint) other) == 0);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 0;
+        if (mInfo != null) result += 13 * mInfo.hashCode();
+        result += 19 * mRssi;
+        result += 23 * networkId;
+        result += 29 * ssid.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder().append("AccessPoint(")
+                .append(ssid);
+        if (isSaved()) {
+            builder.append(',').append("saved");
+        }
+        if (isActive()) {
+            builder.append(',').append("active");
+        }
+        if (isEphemeral()) {
+            builder.append(',').append("ephemeral");
+        }
+        if (isConnectable()) {
+            builder.append(',').append("connectable");
+        }
+        if (security != SECURITY_NONE) {
+            builder.append(',').append(securityToString(security, pskType));
+        }
+        return builder.append(')').toString();
+    }
+
+    public boolean matches(ScanResult result) {
+        return ssid.equals(result.SSID) && security == getSecurity(result);
+    }
+
+    public boolean matches(WifiConfiguration config) {
+        return ssid.equals(removeDoubleQuotes(config.SSID)) && security == getSecurity(config);
+    }
+
+    public WifiConfiguration getConfig() {
+        return mConfig;
+    }
+
+    public void clearConfig() {
+        mConfig = null;
+        networkId = WifiConfiguration.INVALID_NETWORK_ID;
+    }
+
+    public WifiInfo getInfo() {
+        return mInfo;
+    }
+
+    public int getLevel() {
+        if (mRssi == Integer.MAX_VALUE) {
+            return -1;
+        }
+        return WifiManager.calculateSignalLevel(mRssi, 4);
+    }
+
+    public NetworkInfo getNetworkInfo() {
+        return mNetworkInfo;
+    }
+
+    public int getSecurity() {
+        return security;
+    }
+
+    public String getSecurityString(boolean concise) {
+        Context context = mContext;
+        switch(security) {
+            case SECURITY_EAP:
+                return concise ? context.getString(R.string.wifi_security_short_eap) :
+                    context.getString(R.string.wifi_security_eap);
+            case SECURITY_PSK:
+                switch (pskType) {
+                    case PSK_WPA:
+                        return concise ? context.getString(R.string.wifi_security_short_wpa) :
+                            context.getString(R.string.wifi_security_wpa);
+                    case PSK_WPA2:
+                        return concise ? context.getString(R.string.wifi_security_short_wpa2) :
+                            context.getString(R.string.wifi_security_wpa2);
+                    case PSK_WPA_WPA2:
+                        return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) :
+                            context.getString(R.string.wifi_security_wpa_wpa2);
+                    case PSK_UNKNOWN:
+                    default:
+                        return concise ? context.getString(R.string.wifi_security_short_psk_generic)
+                                : context.getString(R.string.wifi_security_psk_generic);
+                }
+            case SECURITY_WEP:
+                return concise ? context.getString(R.string.wifi_security_short_wep) :
+                    context.getString(R.string.wifi_security_wep);
+            case SECURITY_NONE:
+            default:
+                return concise ? "" : context.getString(R.string.wifi_security_none);
+        }
+    }
+
+    public String getSsid() {
+        return ssid;
+    }
+
+    public DetailedState getDetailedState() {
+        return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
+    }
+
+    public String getSummary() {
+        // Update to new summary
+        StringBuilder summary = new StringBuilder();
+
+        if (isActive()) { // This is the active connection
+            summary.append(getSummary(mContext, getDetailedState(),
+                    networkId == WifiConfiguration.INVALID_NETWORK_ID));
+        } else if (mConfig != null
+                && mConfig.hasNoInternetAccess()) {
+            summary.append(mContext.getString(R.string.wifi_no_internet));
+        } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
+                mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
+               || mConfig.autoJoinStatus
+                >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) {
+            if (mConfig.autoJoinStatus
+                    >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
+                if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) {
+                    summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) {
+                    summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
+                } else {
+                    summary.append(mContext.getString(R.string.wifi_disabled_wifi_failure));
+                }
+            } else {
+                switch (mConfig.disableReason) {
+                    case WifiConfiguration.DISABLED_AUTH_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
+                        break;
+                    case WifiConfiguration.DISABLED_DHCP_FAILURE:
+                    case WifiConfiguration.DISABLED_DNS_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                        break;
+                    case WifiConfiguration.DISABLED_UNKNOWN_REASON:
+                    case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
+                        summary.append(mContext.getString(R.string.wifi_disabled_generic));
+                        break;
+                }
+            }
+        } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
+            summary.append(mContext.getString(R.string.wifi_not_in_range));
+        } else { // In range, not disabled.
+            if (mConfig != null) { // Is saved network
+                summary.append(mContext.getString(R.string.wifi_remembered));
+            }
+        }
+
+        if (WifiTracker.sVerboseLogging > 0) {
+            // Add RSSI/band information for this config, what was seen up to 6 seconds ago
+            // verbose WiFi Logging is only turned on thru developers settings
+            if (mInfo != null && mNetworkInfo != null) { // This is the active connection
+                summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
+            }
+            summary.append(" " + getVisibilityStatus());
+            if (mConfig != null && mConfig.autoJoinStatus > 0) {
+                summary.append(" (" + mConfig.autoJoinStatus);
+                if (mConfig.blackListTimestamp > 0) {
+                    long now = System.currentTimeMillis();
+                    long diff = (now - mConfig.blackListTimestamp)/1000;
+                    long sec = diff%60; //seconds
+                    long min = (diff/60)%60; //minutes
+                    long hour = (min/60)%60; //hours
+                    summary.append(", ");
+                    if (hour > 0) summary.append(Long.toString(hour) + "h ");
+                    summary.append( Long.toString(min) + "m ");
+                    summary.append( Long.toString(sec) + "s ");
+                }
+                summary.append(")");
+            }
+            if (mConfig != null && mConfig.numIpConfigFailures > 0) {
+                summary.append(" ipf=").append(mConfig.numIpConfigFailures);
+            }
+            if (mConfig != null && mConfig.numConnectionFailures > 0) {
+                summary.append(" cf=").append(mConfig.numConnectionFailures);
+            }
+            if (mConfig != null && mConfig.numAuthFailures > 0) {
+                summary.append(" authf=").append(mConfig.numAuthFailures);
+            }
+            if (mConfig != null && mConfig.numNoInternetAccessReports > 0) {
+                summary.append(" noInt=").append(mConfig.numNoInternetAccessReports);
+            }
+        }
+        return summary.toString();
+    }
+
+    /**
+     * Returns the visibility status of the WifiConfiguration.
+     *
+     * @return autojoin debugging information
+     * TODO: use a string formatter
+     * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
+     * For instance [-40,5/-30,2]
+     */
+    private String getVisibilityStatus() {
+        StringBuilder visibility = new StringBuilder();
+        StringBuilder scans24GHz = null;
+        StringBuilder scans5GHz = null;
+        String bssid = null;
+
+        long now = System.currentTimeMillis();
+
+        if (mInfo != null) {
+            bssid = mInfo.getBSSID();
+            if (bssid != null) {
+                visibility.append(" ").append(bssid);
+            }
+            visibility.append(" rssi=").append(mInfo.getRssi());
+            visibility.append(" ");
+            visibility.append(" score=").append(mInfo.score);
+            visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
+            visibility.append(String.format("%.1f,", mInfo.txRetriesRate));
+            visibility.append(String.format("%.1f ", mInfo.txBadRate));
+            visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate));
+        }
+
+        if (mScanResultCache != null) {
+            int rssi5 = WifiConfiguration.INVALID_RSSI;
+            int rssi24 = WifiConfiguration.INVALID_RSSI;
+            int num5 = 0;
+            int num24 = 0;
+            int numBlackListed = 0;
+            int n24 = 0; // Number scan results we included in the string
+            int n5 = 0; // Number scan results we included in the string
+            Map<String, ScanResult> list = mScanResultCache.snapshot();
+            // TODO: sort list by RSSI or age
+            for (ScanResult result : list.values()) {
+                if (result.seen == 0)
+                    continue;
+
+                if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++;
+
+                if (result.frequency >= LOWER_FREQ_5GHZ
+                        && result.frequency <= HIGHER_FREQ_5GHZ) {
+                    // Strictly speaking: [4915, 5825]
+                    // number of known BSSID on 5GHz band
+                    num5 = num5 + 1;
+                } else if (result.frequency >= LOWER_FREQ_24GHZ
+                        && result.frequency <= HIGHER_FREQ_24GHZ) {
+                    // Strictly speaking: [2412, 2482]
+                    // number of known BSSID on 2.4Ghz band
+                    num24 = num24 + 1;
+                }
+
+                // Ignore results seen, older than 20 seconds
+                if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue;
+
+                if (result.frequency >= LOWER_FREQ_5GHZ
+                        && result.frequency <= HIGHER_FREQ_5GHZ) {
+                    if (result.level > rssi5) {
+                        rssi5 = result.level;
+                    }
+                    if (n5 < 4) {
+                        if (scans5GHz == null) scans5GHz = new StringBuilder();
+                        scans5GHz.append(" \n{").append(result.BSSID);
+                        if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*");
+                        scans5GHz.append("=").append(result.frequency);
+                        scans5GHz.append(",").append(result.level);
+                        if (result.autoJoinStatus != 0) {
+                            scans5GHz.append(",st=").append(result.autoJoinStatus);
+                        }
+                        if (result.numIpConfigFailures != 0) {
+                            scans5GHz.append(",ipf=").append(result.numIpConfigFailures);
+                        }
+                        scans5GHz.append("}");
+                        n5++;
+                    }
+                } else if (result.frequency >= LOWER_FREQ_24GHZ
+                        && result.frequency <= HIGHER_FREQ_24GHZ) {
+                    if (result.level > rssi24) {
+                        rssi24 = result.level;
+                    }
+                    if (n24 < 4) {
+                        if (scans24GHz == null) scans24GHz = new StringBuilder();
+                        scans24GHz.append(" \n{").append(result.BSSID);
+                        if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*");
+                        scans24GHz.append("=").append(result.frequency);
+                        scans24GHz.append(",").append(result.level);
+                        if (result.autoJoinStatus != 0) {
+                            scans24GHz.append(",st=").append(result.autoJoinStatus);
+                        }
+                        if (result.numIpConfigFailures != 0) {
+                            scans24GHz.append(",ipf=").append(result.numIpConfigFailures);
+                        }
+                        scans24GHz.append("}");
+                        n24++;
+                    }
+                }
+            }
+            visibility.append(" [");
+            if (num24 > 0) {
+                visibility.append("(").append(num24).append(")");
+                if (n24 <= 4) {
+                    if (scans24GHz != null) {
+                        visibility.append(scans24GHz.toString());
+                    }
+                } else {
+                    visibility.append("max=").append(rssi24);
+                    if (scans24GHz != null) {
+                        visibility.append(",").append(scans24GHz.toString());
+                    }
+                }
+            }
+            visibility.append(";");
+            if (num5 > 0) {
+                visibility.append("(").append(num5).append(")");
+                if (n5 <= 4) {
+                    if (scans5GHz != null) {
+                        visibility.append(scans5GHz.toString());
+                    }
+                } else {
+                    visibility.append("max=").append(rssi5);
+                    if (scans5GHz != null) {
+                        visibility.append(",").append(scans5GHz.toString());
+                    }
+                }
+            }
+            if (numBlackListed > 0)
+                visibility.append("!").append(numBlackListed);
+            visibility.append("]");
+        } else {
+            if (mRssi != Integer.MAX_VALUE) {
+                visibility.append(" rssi=");
+                visibility.append(mRssi);
+                if (mScanResult != null) {
+                    visibility.append(", f=");
+                    visibility.append(mScanResult.frequency);
+                }
+            }
+        }
+
+        return visibility.toString();
+    }
+
+    /**
+     * Return whether this is the active connection.
+     * For ephemeral connections (networkId is invalid), this returns false if the network is
+     * disconnected.
+     */
+    public boolean isActive() {
+        return mNetworkInfo != null &&
+                (networkId != WifiConfiguration.INVALID_NETWORK_ID ||
+                 mNetworkInfo.getState() != State.DISCONNECTED);
+    }
+
+    public boolean isConnectable() {
+        return getLevel() != -1 && getDetailedState() == null;
+    }
+
+    public boolean isEphemeral() {
+        return !isSaved() && mNetworkInfo != null && mNetworkInfo.getState() != State.DISCONNECTED;
+    }
+
+    /** Return whether the given {@link WifiInfo} is for this access point. */
+    private boolean isInfoForThisAccessPoint(WifiInfo info) {
+        if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+            return networkId == info.getNetworkId();
+        } else {
+            // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
+            // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
+            // TODO: Handle hex string SSIDs.
+            return ssid.equals(removeDoubleQuotes(info.getSSID()));
+        }
+    }
+
+    public boolean isSaved() {
+        return networkId != WifiConfiguration.INVALID_NETWORK_ID;
+    }
+
+    public Object getTag() {
+        return mTag;
+    }
+
+    public void setTag(Object tag) {
+        mTag = tag;
+    }
+
+    /**
+     * Generate and save a default wifiConfiguration with common values.
+     * Can only be called for unsecured networks.
+     */
+    public void generateOpenNetworkConfig() {
+        if (security != SECURITY_NONE)
+            throw new IllegalStateException();
+        if (mConfig != null)
+            return;
+        mConfig = new WifiConfiguration();
+        mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
+        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+    }
+
+    void loadConfig(WifiConfiguration config) {
+        ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+        security = getSecurity(config);
+        networkId = config.networkId;
+        mConfig = config;
+    }
+
+    private void loadResult(ScanResult result) {
+        ssid = result.SSID;
+        security = getSecurity(result);
+        if (security == SECURITY_PSK)
+            pskType = getPskType(result);
+        mRssi = result.level;
+        mScanResult = result;
+        if (result.seen > mSeen) {
+            mSeen = result.seen;
+        }
+    }
+
+    public void saveWifiState(Bundle savedState) {
+        savedState.putParcelable(KEY_CONFIG, mConfig);
+        savedState.putParcelable(KEY_SCANRESULT, mScanResult);
+        savedState.putParcelable(KEY_WIFIINFO, mInfo);
+        if (mNetworkInfo != null) {
+            savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo);
+        }
+    }
+
+    public void setListener(AccessPointListener listener) {
+        mAccessPointListener = listener;
+    }
+
+    boolean update(ScanResult result) {
+        if (result.seen > mSeen) {
+            mSeen = result.seen;
+        }
+        if (WifiTracker.sVerboseLogging > 0) {
+            if (mScanResultCache == null) {
+                mScanResultCache = new LruCache<String, ScanResult>(32);
+            }
+            mScanResultCache.put(result.BSSID, result);
+        }
+
+        if (ssid.equals(result.SSID) && security == getSecurity(result)) {
+            if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
+                int oldLevel = getLevel();
+                mRssi = result.level;
+                if (getLevel() != oldLevel && mAccessPointListener != null) {
+                    mAccessPointListener.onLevelChanged(this);
+                }
+            }
+            // This flag only comes from scans, is not easily saved in config
+            if (security == SECURITY_PSK) {
+                pskType = getPskType(result);
+            }
+            mScanResult = result;
+            if (mAccessPointListener != null) {
+                mAccessPointListener.onAccessPointChanged(this);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    boolean update(WifiInfo info, NetworkInfo networkInfo) {
+        boolean reorder = false;
+        if (info != null && isInfoForThisAccessPoint(info)) {
+            reorder = (mInfo == null);
+            mRssi = info.getRssi();
+            mInfo = info;
+            mNetworkInfo = networkInfo;
+            if (mAccessPointListener != null) {
+                mAccessPointListener.onAccessPointChanged(this);
+            }
+        } else if (mInfo != null) {
+            reorder = true;
+            mInfo = null;
+            mNetworkInfo = null;
+            if (mAccessPointListener != null) {
+                mAccessPointListener.onAccessPointChanged(this);
+            }
+        }
+        return reorder;
+    }
+
+    public static String getSummary(Context context, String ssid, DetailedState state,
+            boolean isEphemeral) {
+        if (state == DetailedState.CONNECTED && isEphemeral && ssid == null) {
+            // Special case for connected + ephemeral networks.
+            return context.getString(R.string.connected_via_wfa);
+        }
+
+        String[] formats = context.getResources().getStringArray((ssid == null)
+                ? R.array.wifi_status : R.array.wifi_status_with_ssid);
+        int index = state.ordinal();
+
+        if (index >= formats.length || formats[index].length() == 0) {
+            return null;
+        }
+        return String.format(formats[index], ssid);
+    }
+
+    public static String getSummary(Context context, DetailedState state, boolean isEphemeral) {
+        return getSummary(context, null, state, isEphemeral);
+    }
+
+    public static String convertToQuotedString(String string) {
+        return "\"" + string + "\"";
+    }
+
+    private static int getPskType(ScanResult result) {
+        boolean wpa = result.capabilities.contains("WPA-PSK");
+        boolean wpa2 = result.capabilities.contains("WPA2-PSK");
+        if (wpa2 && wpa) {
+            return PSK_WPA_WPA2;
+        } else if (wpa2) {
+            return PSK_WPA2;
+        } else if (wpa) {
+            return PSK_WPA;
+        } else {
+            Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
+            return PSK_UNKNOWN;
+        }
+    }
+
+    private static int getSecurity(ScanResult result) {
+        if (result.capabilities.contains("WEP")) {
+            return SECURITY_WEP;
+        } else if (result.capabilities.contains("PSK")) {
+            return SECURITY_PSK;
+        } else if (result.capabilities.contains("EAP")) {
+            return SECURITY_EAP;
+        }
+        return SECURITY_NONE;
+    }
+
+    static int getSecurity(WifiConfiguration config) {
+        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+            return SECURITY_PSK;
+        }
+        if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+                config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+            return SECURITY_EAP;
+        }
+        return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
+    }
+
+    public static String securityToString(int security, int pskType) {
+        if (security == SECURITY_WEP) {
+            return "WEP";
+        } else if (security == SECURITY_PSK) {
+            if (pskType == PSK_WPA) {
+                return "WPA";
+            } else if (pskType == PSK_WPA2) {
+                return "WPA2";
+            } else if (pskType == PSK_WPA_WPA2) {
+                return "WPA_WPA2";
+            }
+            return "PSK";
+        } else if (security == SECURITY_EAP) {
+            return "EAP";
+        }
+        return "NONE";
+    }
+
+    static String removeDoubleQuotes(String string) {
+        int length = string.length();
+        if ((length > 1) && (string.charAt(0) == '"')
+                && (string.charAt(length - 1) == '"')) {
+            return string.substring(1, length - 1);
+        }
+        return string;
+    }
+
+    public interface AccessPointListener {
+        void onAccessPointChanged(AccessPoint accessPoint);
+        void onLevelChanged(AccessPoint accessPoint);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
new file mode 100644
index 0000000..2eb7abf
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -0,0 +1,480 @@
+/*
+ * 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.settingslib.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Message;
+import android.widget.Toast;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Tracks saved or available wifi networks and their state.
+ */
+public class WifiTracker {
+    private static final String TAG = "WifiTracker";
+
+    /** verbose logging flag. this flag is set thru developer debugging options
+     * and used so as to assist with in-the-field WiFi connectivity debugging  */
+    public static int sVerboseLogging = 0;
+
+    // TODO: Allow control of this?
+    // Combo scans can take 5-6s to complete - set to 10s.
+    private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
+
+    private final Context mContext;
+    private final WifiManager mWifiManager;
+    private final IntentFilter mFilter;
+
+    private final AtomicBoolean mConnected = new AtomicBoolean(false);
+    private final WifiListener mListener;
+    private final boolean mIncludeSaved;
+    private final boolean mIncludeScans;
+
+    private boolean mSavedNetworksExist;
+    private boolean mRegistered;
+    private ArrayList<AccessPoint> mAccessPoints = new ArrayList<>();
+    private ArrayList<AccessPoint> mCachedAccessPoints = new ArrayList<>();
+
+    private NetworkInfo mLastNetworkInfo;
+    private WifiInfo mLastInfo;
+
+    @VisibleForTesting
+    Scanner mScanner;
+
+    public WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
+            boolean includeScans) {
+        this(context, wifiListener, includeSaved, includeScans,
+                (WifiManager) context.getSystemService(Context.WIFI_SERVICE));
+    }
+
+    @VisibleForTesting
+    WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
+            boolean includeScans, WifiManager wifiManager) {
+        if (!includeSaved && !includeScans) {
+            throw new IllegalArgumentException("Must include either saved or scans");
+        }
+        mContext = context;
+        mWifiManager = wifiManager;
+        mIncludeSaved = includeSaved;
+        mIncludeScans = includeScans;
+        mListener = wifiListener;
+
+        // check if verbose logging has been turned on or off
+        sVerboseLogging = mWifiManager.getVerboseLoggingLevel();
+
+        mFilter = new IntentFilter();
+        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+    }
+
+    /**
+     * Forces an update of the wifi networks when not scanning.
+     */
+    public void forceUpdate() {
+        updateAccessPoints();
+    }
+
+    /**
+     * Force a scan for wifi networks to happen now.
+     */
+    public void forceScan() {
+        if (mWifiManager.isWifiEnabled() && mScanner != null) {
+            mScanner.forceScan();
+        }
+    }
+
+    /**
+     * Temporarily stop scanning for wifi networks.
+     */
+    public void pauseScanning() {
+        if (mScanner != null) {
+            mScanner.pause();
+            mScanner = null;
+        }
+    }
+
+    /**
+     * Resume scanning for wifi networks after it has been paused.
+     */
+    public void resumeScanning() {
+        if (mScanner == null) {
+            mScanner = new Scanner();
+        }
+        if (mWifiManager.isWifiEnabled()) {
+            mScanner.resume();
+        }
+        updateAccessPoints();
+    }
+
+    /**
+     * Start tracking wifi networks.
+     * Registers listeners and starts scanning for wifi networks. If this is not called
+     * then forceUpdate() must be called to populate getAccessPoints().
+     */
+    public void startTracking() {
+        resumeScanning();
+        if (!mRegistered) {
+            mContext.registerReceiver(mReceiver, mFilter);
+            mRegistered = true;
+        }
+    }
+
+    /**
+     * Stop tracking wifi networks.
+     * Unregisters all listeners and stops scanning for wifi networks. This should always
+     * be called when done with a WifiTracker (if startTracking was called) to ensure
+     * proper cleanup.
+     */
+    public void stopTracking() {
+        if (mRegistered) {
+            mContext.unregisterReceiver(mReceiver);
+            mRegistered = false;
+        }
+        pauseScanning();
+    }
+
+    /**
+     * Gets the current list of access points.
+     */
+    public List<AccessPoint> getAccessPoints() {
+        return mAccessPoints;
+    }
+
+    public WifiManager getManager() {
+        return mWifiManager;
+    }
+
+    public boolean isWifiEnabled() {
+        return mWifiManager.isWifiEnabled();
+    }
+
+    /**
+     * @return true when there are saved networks on the device, regardless
+     * of whether the WifiTracker is tracking saved networks.
+     */
+    public boolean doSavedNetworksExist() {
+        return mSavedNetworksExist;
+    }
+
+    public boolean isConnected() {
+        return mConnected.get();
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("  - wifi tracker ------");
+        for (AccessPoint accessPoint : mAccessPoints) {
+            pw.println("  " + accessPoint);
+        }
+    }
+
+    private void updateAccessPoints() {
+        // Swap the current access points into a cached list.
+        ArrayList<AccessPoint> tmpSwp = mAccessPoints;
+        mAccessPoints = mCachedAccessPoints;
+        mCachedAccessPoints = tmpSwp;
+        // Clear out the configs so we don't think something is saved when it isn't.
+        for (AccessPoint accessPoint : mCachedAccessPoints) {
+            accessPoint.clearConfig();
+        }
+
+        mAccessPoints.clear();
+
+        /** Lookup table to more quickly update AccessPoints by only considering objects with the
+         * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
+        Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
+
+        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        if (configs != null) {
+            mSavedNetworksExist = configs.size() != 0;
+            for (WifiConfiguration config : configs) {
+                if (config.selfAdded && config.numAssociation == 0) {
+                    continue;
+                }
+                AccessPoint accessPoint = getCachedOrCreate(config);
+                if (mLastInfo != null && mLastNetworkInfo != null) {
+                    accessPoint.update(mLastInfo, mLastNetworkInfo);
+                }
+                if (mIncludeSaved) {
+                    mAccessPoints.add(accessPoint);
+                    apMap.put(accessPoint.getSsid(), accessPoint);
+                } else {
+                    // If we aren't using saved networks, drop them into the cache so that
+                    // we have access to their saved info.
+                    mCachedAccessPoints.add(accessPoint);
+                }
+            }
+        }
+
+        final List<ScanResult> results = mWifiManager.getScanResults();
+        if (results != null) {
+            for (ScanResult result : results) {
+                // Ignore hidden and ad-hoc networks.
+                if (result.SSID == null || result.SSID.length() == 0 ||
+                        result.capabilities.contains("[IBSS]")) {
+                    continue;
+                }
+
+                boolean found = false;
+                for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
+                    if (accessPoint.update(result)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found && mIncludeScans) {
+                    AccessPoint accessPoint = getCachedOrCreate(result);
+                    if (mLastInfo != null && mLastNetworkInfo != null) {
+                        accessPoint.update(mLastInfo, mLastNetworkInfo);
+                    }
+                    mAccessPoints.add(accessPoint);
+                    apMap.put(accessPoint.getSsid(), accessPoint);
+                }
+            }
+        }
+
+        // Pre-sort accessPoints to speed preference insertion
+        Collections.sort(mAccessPoints);
+        if (mListener != null) {
+            mListener.onAccessPointsChanged();
+        }
+    }
+
+    private AccessPoint getCachedOrCreate(ScanResult result) {
+        final int N = mCachedAccessPoints.size();
+        for (int i = 0; i < N; i++) {
+            if (mCachedAccessPoints.get(i).matches(result)) {
+                AccessPoint ret = mCachedAccessPoints.remove(i);
+                ret.update(result);
+                return ret;
+            }
+        }
+        return new AccessPoint(mContext, result);
+    }
+
+    private AccessPoint getCachedOrCreate(WifiConfiguration config) {
+        final int N = mCachedAccessPoints.size();
+        for (int i = 0; i < N; i++) {
+            if (mCachedAccessPoints.get(i).matches(config)) {
+                AccessPoint ret = mCachedAccessPoints.remove(i);
+                ret.loadConfig(config);
+                return ret;
+            }
+        }
+        return new AccessPoint(mContext, config);
+    }
+
+    private void updateNetworkInfo(NetworkInfo networkInfo) {
+        /* sticky broadcasts can call this when wifi is disabled */
+        if (!mWifiManager.isWifiEnabled()) {
+            mScanner.pause();
+            return;
+        }
+
+        if (networkInfo != null &&
+                networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
+            mScanner.pause();
+        } else {
+            mScanner.resume();
+        }
+
+        mLastInfo = mWifiManager.getConnectionInfo();
+        if (networkInfo != null) {
+            mLastNetworkInfo = networkInfo;
+        }
+
+        boolean reorder = false;
+        for (int i = mAccessPoints.size() - 1; i >= 0; --i) {
+            if (mAccessPoints.get(i).update(mLastInfo, mLastNetworkInfo)) {
+                reorder = true;
+            }
+        }
+        if (reorder) {
+            Collections.sort(mAccessPoints);
+            if (mListener != null) {
+                mListener.onAccessPointsChanged();
+            }
+        }
+    }
+
+    private void updateWifiState(int state) {
+        if (state == WifiManager.WIFI_STATE_ENABLED) {
+            if (mScanner != null) {
+                // We only need to resume if mScanner isn't null because
+                // that means we want to be scanning.
+                mScanner.resume();
+            }
+        } else {
+            mLastInfo = null;
+            mLastNetworkInfo = null;
+            if (mScanner != null) {
+                mScanner.pause();
+            }
+        }
+        if (mListener != null) {
+            mListener.onWifiStateChanged(state);
+        }
+    }
+
+    public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
+            boolean includeScans) {
+        WifiTracker tracker = new WifiTracker(context, null, includeSaved, includeScans);
+        tracker.forceUpdate();
+        return tracker.getAccessPoints();
+    }
+
+    @VisibleForTesting
+    final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+                updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                        WifiManager.WIFI_STATE_UNKNOWN));
+            } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
+                    WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
+                    WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
+                updateAccessPoints();
+            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+                NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_INFO);
+                mConnected.set(info.isConnected());
+                if (mListener != null) {
+                    mListener.onConnectedChanged();
+                }
+                updateAccessPoints();
+                updateNetworkInfo(info);
+            } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
+                updateNetworkInfo(null);
+            }
+        }
+    };
+
+    @VisibleForTesting
+    class Scanner extends Handler {
+        private static final int MSG_SCAN = 0;
+
+        private int mRetry = 0;
+
+        void resume() {
+            if (!hasMessages(MSG_SCAN)) {
+                sendEmptyMessage(MSG_SCAN);
+            }
+        }
+
+        void forceScan() {
+            removeMessages(MSG_SCAN);
+            sendEmptyMessage(MSG_SCAN);
+        }
+
+        void pause() {
+            mRetry = 0;
+            removeMessages(MSG_SCAN);
+        }
+
+        @VisibleForTesting
+        boolean isScanning() {
+            return hasMessages(MSG_SCAN);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what != MSG_SCAN) return;
+            if (mWifiManager.startScan()) {
+                mRetry = 0;
+            } else if (++mRetry >= 3) {
+                mRetry = 0;
+                if (mContext != null) {
+                    Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
+                }
+                return;
+            }
+            sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
+        }
+    }
+
+    /** A restricted multimap for use in constructAccessPoints */
+    private static class Multimap<K,V> {
+        private final HashMap<K,List<V>> store = new HashMap<K,List<V>>();
+        /** retrieve a non-null list of values with key K */
+        List<V> getAll(K key) {
+            List<V> values = store.get(key);
+            return values != null ? values : Collections.<V>emptyList();
+        }
+
+        void put(K key, V val) {
+            List<V> curVals = store.get(key);
+            if (curVals == null) {
+                curVals = new ArrayList<V>(3);
+                store.put(key, curVals);
+            }
+            curVals.add(val);
+        }
+    }
+
+    public interface WifiListener {
+        /**
+         * Called when the state of Wifi has changed, the state will be one of
+         * the following.
+         *
+         * <li>{@link WifiManager#WIFI_STATE_DISABLED}</li>
+         * <li>{@link WifiManager#WIFI_STATE_ENABLED}</li>
+         * <li>{@link WifiManager#WIFI_STATE_DISABLING}</li>
+         * <li>{@link WifiManager#WIFI_STATE_ENABLING}</li>
+         * <li>{@link WifiManager#WIFI_STATE_UNKNOWN}</li>
+         * <p>
+         *
+         * @param state The new state of wifi.
+         */
+        void onWifiStateChanged(int state);
+
+        /**
+         * Called when the connection state of wifi has changed and isConnected
+         * should be called to get the updated state.
+         */
+        void onConnectedChanged();
+
+        /**
+         * Called to indicate the list of AccessPoints has been updated and
+         * getAccessPoints should be called to get the latest information.
+         */
+        void onAccessPointsChanged();
+    }
+}
diff --git a/packages/SettingsLib/tests/Android.mk b/packages/SettingsLib/tests/Android.mk
new file mode 100644
index 0000000..d3ffffa
--- /dev/null
+++ b/packages/SettingsLib/tests/Android.mk
@@ -0,0 +1,30 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+
+LOCAL_PACKAGE_NAME := SettingsLibTests
+
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+
+include frameworks/base/packages/SettingsLib/common.mk
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/tests/AndroidManifest.xml b/packages/SettingsLib/tests/AndroidManifest.xml
new file mode 100644
index 0000000..00d16fc
--- /dev/null
+++ b/packages/SettingsLib/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.settingslib">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.settingslib"
+        android:label="Tests for SettingsLib">
+    </instrumentation>
+</manifest>
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/BaseTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/BaseTest.java
new file mode 100644
index 0000000..04a568e
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/BaseTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.settingslib;
+
+import android.test.AndroidTestCase;
+
+public class BaseTest extends AndroidTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Mockito stuff.
+        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+    }
+
+}
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
new file mode 100644
index 0000000..4ac461d
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.settingslib.wifi;
+
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+
+import com.android.settingslib.BaseTest;
+import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+// TODO: Add some coverage
+public class AccessPointTest extends BaseTest {
+
+    private static final String TEST_SSID = "TestSsid";
+    private static final int NETWORK_ID = 0;
+
+    private AccessPointListener mAccessPointListener;
+    private AccessPoint mAccessPoint;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAccessPointListener = Mockito.mock(AccessPointListener.class);
+
+        WifiConfiguration wifiConfig = new WifiConfiguration();
+        wifiConfig.networkId = NETWORK_ID;
+        wifiConfig.SSID = TEST_SSID;
+
+        mAccessPoint = new AccessPoint(mContext, wifiConfig);
+        mAccessPoint.setListener(mAccessPointListener);
+    }
+
+    public void testOnLevelChanged() {
+        ScanResult result = new ScanResult();
+        result.capabilities = "";
+        result.SSID = TEST_SSID;
+
+        // Give it a level.
+        result.level = WifiTrackerTest.levelToRssi(1);
+        mAccessPoint.update(result);
+        verifyOnLevelChangedCallback(1);
+
+        // Give it a better level.
+        result.level = WifiTrackerTest.levelToRssi(2);
+        mAccessPoint.update(result);
+        verifyOnLevelChangedCallback(1);
+    }
+
+    public void testOnAccessPointChangedCallback() {
+        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
+        Mockito.when(wifiInfo.getNetworkId()).thenReturn(NETWORK_ID);
+
+        mAccessPoint.update(wifiInfo, null);
+        verifyOnAccessPointsCallback(1);
+
+        mAccessPoint.update(null, null);
+        verifyOnAccessPointsCallback(2);
+
+        ScanResult result = new ScanResult();
+        result.capabilities = "";
+        result.SSID = TEST_SSID;
+        mAccessPoint.update(result);
+        verifyOnAccessPointsCallback(3);
+    }
+
+    private void verifyOnLevelChangedCallback(int num) {
+        ArgumentCaptor<AccessPoint> accessPoint = ArgumentCaptor.forClass(AccessPoint.class);
+        Mockito.verify(mAccessPointListener, Mockito.atLeast(num))
+                .onLevelChanged(accessPoint.capture());
+        assertEquals(mAccessPoint, accessPoint.getValue());
+    }
+
+    private void verifyOnAccessPointsCallback(int num) {
+        ArgumentCaptor<AccessPoint> accessPoint = ArgumentCaptor.forClass(AccessPoint.class);
+        Mockito.verify(mAccessPointListener, Mockito.atLeast(num))
+                .onAccessPointChanged(accessPoint.capture());
+        assertEquals(mAccessPoint, accessPoint.getValue());
+    }
+
+}
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
new file mode 100644
index 0000000..8eb1ca4
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -0,0 +1,307 @@
+/*
+ * 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.settingslib.wifi;
+
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.util.Log;
+
+import com.android.settingslib.BaseTest;
+import com.android.settingslib.wifi.WifiTracker.WifiListener;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class WifiTrackerTest extends BaseTest {
+
+    private static final String TAG = "WifiTrackerTest";
+
+    private static final String[] TEST_SSIDS = new String[] {
+        "TEST_SSID_1",
+        "TEST_SSID_2",
+        "TEST_SSID_3",
+        "TEST_SSID_4",
+        "TEST_SSID_5",
+    };
+    private static final int NUM_NETWORKS = 5;
+
+    private WifiManager mWifiManager;
+    private WifiListener mWifiListener;
+
+    private WifiTracker mWifiTracker;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mWifiManager = Mockito.mock(WifiManager.class);
+        mWifiListener = Mockito.mock(WifiListener.class);
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, true, true, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+        Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(true);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        mWifiTracker.dump(pw);
+        pw.flush();
+        Log.d(TAG, sw.toString());
+        super.tearDown();
+    }
+
+    public void testAccessPointsCallback() {
+        sendScanResultsAvailable();
+
+        Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onAccessPointsChanged();
+    }
+
+    public void testConnectedCallback() {
+        sendConnected();
+
+        Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onConnectedChanged();
+        assertEquals(true, mWifiTracker.isConnected());
+    }
+
+    public void testWifiStateCallback() {
+        final int TEST_WIFI_STATE = WifiManager.WIFI_STATE_ENABLED;
+
+        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, TEST_WIFI_STATE);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+
+        ArgumentCaptor<Integer> wifiState = ArgumentCaptor.forClass(Integer.class);
+        Mockito.verify(mWifiListener, Mockito.atLeastOnce())
+                .onWifiStateChanged(wifiState.capture());
+        assertEquals(TEST_WIFI_STATE, (int) wifiState.getValue());
+    }
+
+    public void testScanner() {
+        // TODO: Figure out how to verify more of the Scanner functionality.
+        // Make scans be successful.
+        Mockito.when(mWifiManager.startScan()).thenReturn(true);
+
+        mWifiTracker.mScanner.handleMessage(null);
+        Mockito.verify(mWifiManager, Mockito.atLeastOnce()).startScan();
+    }
+
+    public void testNetworkSorting() {
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        assertEquals("Expected number of results", NUM_NETWORKS, accessPoints.size());
+        for (int i = 0; i < NUM_NETWORKS; i++) {
+            assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
+        }
+    }
+
+    public void testSavedOnly() {
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, true, false, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        generateTestNetworks(wifiConfigs, scanResults, true);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        // Only expect the first two to come back in the results.
+        assertEquals("Expected number of results", 2, accessPoints.size());
+        assertEquals(TEST_SSIDS[1], accessPoints.get(0).getSsid());
+        assertEquals(TEST_SSIDS[0], accessPoints.get(1).getSsid());
+    }
+
+    public void testAvailableOnly() {
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, false, true, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+
+        // Expect the last one (sorted order) to be left off since its only saved.
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
+        for (int i = 0; i < NUM_NETWORKS - 1; i++) {
+            assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
+        }
+    }
+
+    public void testNonEphemeralConnected() {
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, false, true, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, false);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+        // Do this twice to catch a bug that was happening in the caching, making things ephemeral.
+        sendScanResultsAvailable();
+
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
+        assertFalse("Connection is not ephemeral", accessPoints.get(0).isEphemeral());
+        assertTrue("Connected to wifi", accessPoints.get(0).isActive());
+    }
+
+    public void testEnableResumeScanning() {
+        mWifiTracker.mScanner = null;
+
+        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        // Make sure disable/enable cycle works with no scanner (no crashing).
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+
+        Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(false);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+        // Now enable scanning while wifi is off, it shouldn't start.
+        mWifiTracker.resumeScanning();
+        assertFalse(mWifiTracker.mScanner.isScanning());
+
+        // Turn on wifi and make sure scanning starts.
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+        assertTrue(mWifiTracker.mScanner.isScanning());
+    }
+
+    private String[] generateTestNetworks(List<WifiConfiguration> wifiConfigs,
+            List<ScanResult> scanResults, boolean connectedIsEphemeral) {
+        String[] expectedSsids = new String[NUM_NETWORKS];
+
+        // First is just saved;
+        addConfig(wifiConfigs, TEST_SSIDS[0]);
+        // This should come last since its not available.
+        expectedSsids[4] = TEST_SSIDS[0];
+
+        // Second is saved and available.
+        addConfig(wifiConfigs, TEST_SSIDS[1]);
+        addResult(scanResults, TEST_SSIDS[1], 0);
+        // This one is going to have a couple extra results, to verify de-duplication.
+        addResult(scanResults, TEST_SSIDS[1], 2);
+        addResult(scanResults, TEST_SSIDS[1], 1);
+        // This should come second since it is available and saved but not connected.
+        expectedSsids[1] = TEST_SSIDS[1];
+
+        // Third is just available, but higher rssi.
+        addResult(scanResults, TEST_SSIDS[2], 3);
+        // This comes after the next one since it has a lower rssi.
+        expectedSsids[3] = TEST_SSIDS[2];
+
+        // Fourth also just available but with even higher rssi.
+        addResult(scanResults, TEST_SSIDS[3], 4);
+        // This is the highest rssi but not saved so it should be after the saved+availables.
+        expectedSsids[2] = TEST_SSIDS[3];
+
+        // Last is going to be connected.
+        int netId = WifiConfiguration.INVALID_NETWORK_ID;
+        if (!connectedIsEphemeral) {
+            netId = addConfig(wifiConfigs, TEST_SSIDS[4]);
+        }
+        addResult(scanResults, TEST_SSIDS[4], 2);
+        // Setup wifi connection to be this one.
+        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
+        Mockito.when(wifiInfo.getSSID()).thenReturn(TEST_SSIDS[4]);
+        Mockito.when(wifiInfo.getNetworkId()).thenReturn(netId);
+        Mockito.when(mWifiManager.getConnectionInfo()).thenReturn(wifiInfo);
+        // This should come first since it is connected.
+        expectedSsids[0] = TEST_SSIDS[4];
+
+        return expectedSsids;
+    }
+
+    private void addResult(List<ScanResult> results, String ssid, int level) {
+        results.add(new ScanResult(WifiSsid.createFromAsciiEncoded(ssid),
+                ssid, ssid, levelToRssi(level), AccessPoint.LOWER_FREQ_24GHZ, 0));
+    }
+
+    public static int levelToRssi(int level) {
+        // Reverse level to rssi calculation based off from WifiManager.calculateSignalLevel.
+        final int MAX_RSSI = -55;
+        final int MIN_RSSI = -100;
+        final int NUM_LEVELS = 4;
+        return level * (MAX_RSSI - MIN_RSSI) / (NUM_LEVELS - 1) + MIN_RSSI;
+    }
+
+    private int addConfig(List<WifiConfiguration> configs, String ssid) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = configs.size();
+        config.SSID = '"' + ssid + '"';
+        configs.add(config);
+        return config.networkId;
+    }
+
+    private void sendConnected() {
+        NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
+        Mockito.when(networkInfo.isConnected()).thenReturn(true);
+        Mockito.when(networkInfo.getState()).thenReturn(State.CONNECTED);
+        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+        mWifiTracker.mReceiver.onReceive(mContext, intent);
+    }
+
+    private void sendScanResultsAvailable() {
+        Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+    }
+
+}
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index c16f7b6..2b833b2 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -3,7 +3,8 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+    src/com/android/providers/settings/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := telephony-common ims-common
 
diff --git a/packages/SettingsProvider/res/values-tl/strings.xml b/packages/SettingsProvider/res/values-tl/strings.xml
index 19219ec..0fe535e 100644
--- a/packages/SettingsProvider/res/values-tl/strings.xml
+++ b/packages/SettingsProvider/res/values-tl/strings.xml
@@ -19,5 +19,5 @@
 
 <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="4567566098528588863">"Imbakan ng Mga Setting"</string>
+    <string name="app_label" msgid="4567566098528588863">"Storage ng Mga Setting"</string>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 175b424..729efcb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -28,8 +28,8 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
+import android.media.AudioSystem;
 import android.media.AudioManager;
-import android.media.AudioService;
 import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Environment;
@@ -58,6 +58,7 @@
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Database helper class for {@link SettingsProvider}.
@@ -78,6 +79,9 @@
 
     private static final HashSet<String> mValidTables = new HashSet<String>();
 
+    private static final String DATABASE_JOURNAL_SUFFIX = "-journal";
+    private static final String DATABASE_BACKUP_SUFFIX = "-backup";
+
     private static final String TABLE_SYSTEM = "system";
     private static final String TABLE_SECURE = "secure";
     private static final String TABLE_GLOBAL = "global";
@@ -86,13 +90,13 @@
         mValidTables.add(TABLE_SYSTEM);
         mValidTables.add(TABLE_SECURE);
         mValidTables.add(TABLE_GLOBAL);
-        mValidTables.add("bluetooth_devices");
-        mValidTables.add("bookmarks");
 
         // These are old.
+        mValidTables.add("bluetooth_devices");
+        mValidTables.add("bookmarks");
         mValidTables.add("favorites");
-        mValidTables.add("gservices");
         mValidTables.add("old_favorites");
+        mValidTables.add("android_metadata");
     }
 
     static String dbNameForUser(final int userHandle) {
@@ -118,6 +122,33 @@
         return mValidTables.contains(name);
     }
 
+    public void dropDatabase() {
+        close();
+        File databaseFile = mContext.getDatabasePath(getDatabaseName());
+        if (databaseFile.exists()) {
+            databaseFile.delete();
+        }
+        File databaseJournalFile = mContext.getDatabasePath(getDatabaseName()
+                + DATABASE_JOURNAL_SUFFIX);
+        if (databaseJournalFile.exists()) {
+            databaseJournalFile.delete();
+        }
+    }
+
+    public void backupDatabase() {
+        close();
+        File databaseFile = mContext.getDatabasePath(getDatabaseName());
+        if (!databaseFile.exists()) {
+            return;
+        }
+        File backupFile = mContext.getDatabasePath(getDatabaseName()
+                + DATABASE_BACKUP_SUFFIX);
+        if (backupFile.exists()) {
+            return;
+        }
+        databaseFile.renameTo(backupFile);
+    }
+
     private void createSecureTable(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE secure (" +
                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
@@ -568,7 +599,7 @@
                 stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
                         + " VALUES(?,?);");
                 loadSetting(stmt, Settings.System.VOLUME_BLUETOOTH_SCO,
-                        AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
+                        AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
                 db.setTransactionSuccessful();
             } finally {
                 db.endTransaction();
@@ -1221,9 +1252,11 @@
                     // Migrate now-global settings. Note that this happens before
                     // new users can be created.
                     createGlobalTable(db);
-                    String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+                    String[] settingsToMove = setToStringArray(
+                            SettingsProvider.sSystemMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, false);
-                    settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+                    settingsToMove = setToStringArray(
+                            SettingsProvider.sSecureMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, false);
 
                     db.setTransactionSuccessful();
@@ -1489,9 +1522,11 @@
                 db.beginTransaction();
                 try {
                     // Migrate now-global settings
-                    String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+                    String[] settingsToMove = setToStringArray(
+                            SettingsProvider.sSystemMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
-                    settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+                    settingsToMove = setToStringArray(
+                            SettingsProvider.sSecureMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
 
                     db.setTransactionSuccessful();
@@ -1855,7 +1890,8 @@
                 try {
                     stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
                             + " VALUES(?,?);");
-                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
+                            ImsConfig.FeatureValueConstants.ON);
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();
@@ -1895,34 +1931,50 @@
             }
             upgradeVersion = 118;
         }
+
+        /**
+         * IMPORTANT: Do not add any more upgrade steps here as the global,
+         * secure, and system settings are no longer stored in a database
+         * but are kept in memory and persisted to XML. The correct places
+         * for adding upgrade steps are:
+         *
+         * Global: SettingsProvider.UpgradeController#onUpgradeGlobalSettings
+         * Secure: SettingsProvider.UpgradeController#onUpgradeSecureSettings
+         * System: SettingsProvider.UpgradeController#onUpgradeSystemSettings
+         */
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
-            Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
-                    + ", must wipe the settings provider");
-            db.execSQL("DROP TABLE IF EXISTS global");
-            db.execSQL("DROP TABLE IF EXISTS globalIndex1");
-            db.execSQL("DROP TABLE IF EXISTS system");
-            db.execSQL("DROP INDEX IF EXISTS systemIndex1");
-            db.execSQL("DROP TABLE IF EXISTS secure");
-            db.execSQL("DROP INDEX IF EXISTS secureIndex1");
-            db.execSQL("DROP TABLE IF EXISTS gservices");
-            db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
-            db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
-            db.execSQL("DROP TABLE IF EXISTS bookmarks");
-            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
-            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
-            db.execSQL("DROP TABLE IF EXISTS favorites");
-            onCreate(db);
-
-            // Added for diagnosing settings.db wipes after the fact
-            String wipeReason = oldVersion + "/" + upgradeVersion + "/" + currentVersion;
-            db.execSQL("INSERT INTO secure(name,value) values('" +
-                    "wiped_db_reason" + "','" + wipeReason + "');");
+            recreateDatabase(db, oldVersion, upgradeVersion, currentVersion);
         }
     }
 
-    private String[] hashsetToStringArray(HashSet<String> set) {
+    public void recreateDatabase(SQLiteDatabase db, int oldVersion,
+            int upgradeVersion, int currentVersion) {
+        db.execSQL("DROP TABLE IF EXISTS global");
+        db.execSQL("DROP TABLE IF EXISTS globalIndex1");
+        db.execSQL("DROP TABLE IF EXISTS system");
+        db.execSQL("DROP INDEX IF EXISTS systemIndex1");
+        db.execSQL("DROP TABLE IF EXISTS secure");
+        db.execSQL("DROP INDEX IF EXISTS secureIndex1");
+        db.execSQL("DROP TABLE IF EXISTS gservices");
+        db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
+        db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
+        db.execSQL("DROP TABLE IF EXISTS bookmarks");
+        db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
+        db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
+        db.execSQL("DROP TABLE IF EXISTS favorites");
+
+        onCreate(db);
+
+        // Added for diagnosing settings.db wipes after the fact
+        String wipeReason = oldVersion + "/" + upgradeVersion + "/" + currentVersion;
+        db.execSQL("INSERT INTO secure(name,value) values('" +
+                "wiped_db_reason" + "','" + wipeReason + "');");
+    }
+
+    private String[] setToStringArray(Set<String> set) {
         String[] array = new String[set.size()];
         return set.toArray(array);
     }
@@ -2051,11 +2103,11 @@
         int vibrateSetting = getIntValueFromSystem(db, Settings.System.VIBRATE_ON, 0);
         // If the ringer vibrate value is invalid, set it to the default
         if ((vibrateSetting & 3) == AudioManager.VIBRATE_SETTING_OFF) {
-            vibrateSetting = AudioService.getValueForVibrateSetting(0,
+            vibrateSetting = AudioSystem.getValueForVibrateSetting(0,
                     AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
         }
         // Apply the same setting to the notification vibrate value
-        vibrateSetting = AudioService.getValueForVibrateSetting(vibrateSetting,
+        vibrateSetting = AudioSystem.getValueForVibrateSetting(vibrateSetting,
                 AudioManager.VIBRATE_TYPE_NOTIFICATION, vibrateSetting);
 
         SQLiteStatement stmt = null;
@@ -2199,25 +2251,25 @@
                     + " VALUES(?,?);");
 
             loadSetting(stmt, Settings.System.VOLUME_MUSIC,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));
             loadSetting(stmt, Settings.System.VOLUME_RING,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_RING));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_RING));
             loadSetting(stmt, Settings.System.VOLUME_SYSTEM,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));
             loadSetting(
                     stmt,
                     Settings.System.VOLUME_VOICE,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));
             loadSetting(stmt, Settings.System.VOLUME_ALARM,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_ALARM));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_ALARM));
             loadSetting(
                     stmt,
                     Settings.System.VOLUME_NOTIFICATION,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));
             loadSetting(
                     stmt,
                     Settings.System.VOLUME_BLUETOOTH_SCO,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
 
             // By default:
             // - ringtones, notification, system and music streams are affected by ringer mode
@@ -2236,10 +2288,7 @@
                     ringerModeAffectedStreams);
 
             loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
-                    ((1 << AudioManager.STREAM_MUSIC) |
-                     (1 << AudioManager.STREAM_RING) |
-                     (1 << AudioManager.STREAM_NOTIFICATION) |
-                     (1 << AudioManager.STREAM_SYSTEM)));
+                    AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED);
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -2259,10 +2308,10 @@
 
             // Vibrate on by default for ringer, on for notification
             int vibrate = 0;
-            vibrate = AudioService.getValueForVibrateSetting(vibrate,
+            vibrate = AudioSystem.getValueForVibrateSetting(vibrate,
                     AudioManager.VIBRATE_TYPE_NOTIFICATION,
                     AudioManager.VIBRATE_SETTING_ONLY_SILENT);
-            vibrate |= AudioService.getValueForVibrateSetting(vibrate,
+            vibrate |= AudioSystem.getValueForVibrateSetting(vibrate,
                     AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
             loadSetting(stmt, Settings.System.VIBRATE_ON, vibrate);
         } finally {
@@ -2642,7 +2691,8 @@
 
             loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
                     R.bool.def_guest_user_enabled);
-            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
+                    ImsConfig.FeatureValueConstants.ON);
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags
new file mode 100644
index 0000000..298d776
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags
@@ -0,0 +1,5 @@
+# See system/core/logcat/e for a description of the format of this file.
+
+option java_package com.android.providers.settings;
+
+52100 unsupported_settings_query (uri|3),(selection|3),(whereArgs|3)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 264dcae..8371117 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -110,11 +110,7 @@
 
     private static final String TAG = "SettingsBackupAgent";
 
-    private static final int COLUMN_NAME = 1;
-    private static final int COLUMN_VALUE = 2;
-
     private static final String[] PROJECTION = {
-        Settings.NameValueTable._ID,
         Settings.NameValueTable.NAME,
         Settings.NameValueTable.VALUE
     };
@@ -473,8 +469,8 @@
             ParcelFileDescriptor newState) throws IOException {
 
         HashSet<String> movedToGlobal = new HashSet<String>();
-        Settings.System.getMovedKeys(movedToGlobal);
-        Settings.Secure.getMovedKeys(movedToGlobal);
+        Settings.System.getMovedToGlobalSettings(movedToGlobal);
+        Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
 
         while (data.readNextHeader()) {
             final String key = data.getKey();
@@ -577,8 +573,8 @@
         if (version <= FULL_BACKUP_VERSION) {
             // Generate the moved-to-global lookup table
             HashSet<String> movedToGlobal = new HashSet<String>();
-            Settings.System.getMovedKeys(movedToGlobal);
-            Settings.Secure.getMovedKeys(movedToGlobal);
+            Settings.System.getMovedToGlobalSettings(movedToGlobal);
+            Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
 
             // system settings data first
             int nBytes = in.readInt();
@@ -824,11 +820,14 @@
             String key = settings[i];
             String value = cachedEntries.remove(key);
 
+            final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+            final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
             // If the value not cached, let us look it up.
             if (value == null) {
                 while (!cursor.isAfterLast()) {
-                    String cursorKey = cursor.getString(COLUMN_NAME);
-                    String cursorValue = cursor.getString(COLUMN_VALUE);
+                    String cursorKey = cursor.getString(nameColumnIndex);
+                    String cursorValue = cursor.getString(valueColumnIndex);
                     cursor.moveToNext();
                     if (key.equals(cursorKey)) {
                         value = cursorValue;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6828301..ff2c004 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -16,1211 +16,461 @@
 
 package com.android.providers.settings;
 
-import java.io.FileNotFoundException;
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
-import android.content.ContentUris;
 import android.content.ContentValues;
 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.UserInfo;
-import android.database.AbstractCursor;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteQueryBuilder;
+import android.hardware.camera2.utils.ArrayUtils;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.DropBoxManager;
-import android.os.FileObserver;
+import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.text.TextUtils;
-import android.util.Log;
-import android.util.LruCache;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
 
+import com.android.providers.settings.SettingsState.Setting;
+
+/**
+ * <p>
+ * This class is a content provider that publishes the system settings.
+ * It can be accessed via the content provider APIs or via custom call
+ * commands. The latter is a bit faster and is the preferred way to access
+ * the platform settings.
+ * </p>
+ * <p>
+ * There are three settings types, global (with signature level protection
+ * and shared across users), secure (with signature permission level
+ * protection and per user), and system (with dangerous permission level
+ * protection and per user). Global settings are stored under the device owner.
+ * Each of these settings is represented by a {@link
+ * com.android.providers.settings.SettingsState} object mapped to an integer
+ * key derived from the setting type in the most significant bits and user
+ * id in the least significant bits. Settings are synchronously loaded on
+ * instantiation of a SettingsState and asynchronously persisted on mutation.
+ * Settings are stored in the user specific system directory.
+ * </p>
+ * <p>
+ * Apps targeting APIs Lollipop MR1 and lower can add custom settings entries
+ * and get a warning. Targeting higher API version prohibits this as the
+ * system settings are not a place for apps to save their state. When a package
+ * is removed the settings it added are deleted. Apps cannot delete system
+ * settings added by the platform. System settings values are validated to
+ * ensure the clients do not put bad values. Global and secure settings are
+ * changed only by trusted parties, therefore no validation is performed. Also
+ * there is a limit on the amount of app specific settings that can be added
+ * to prevent unlimited growth of the system process memory footprint.
+ * </p>
+ */
+@SuppressWarnings("deprecation")
 public class SettingsProvider extends ContentProvider {
-    private static final String TAG = "SettingsProvider";
-    private static final boolean LOCAL_LOGV = false;
+    private static final boolean DEBUG = false;
 
-    private static final boolean USER_CHECK_THROWS = true;
+    private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
+
+    private static final String LOG_TAG = "SettingsProvider";
 
     private static final String TABLE_SYSTEM = "system";
     private static final String TABLE_SECURE = "secure";
     private static final String TABLE_GLOBAL = "global";
+
+    // Old tables no longer exist.
     private static final String TABLE_FAVORITES = "favorites";
     private static final String TABLE_OLD_FAVORITES = "old_favorites";
+    private static final String TABLE_BLUETOOTH_DEVICES = "bluetooth_devices";
+    private static final String TABLE_BOOKMARKS = "bookmarks";
+    private static final String TABLE_ANDROID_METADATA = "android_metadata";
 
-    private static final String[] COLUMN_VALUE = new String[] { "value" };
-
-    // Caches for each user's settings, access-ordered for acting as LRU.
-    // Guarded by themselves.
-    private static final int MAX_CACHE_ENTRIES = 200;
-    private static final SparseArray<SettingsCache> sSystemCaches
-            = new SparseArray<SettingsCache>();
-    private static final SparseArray<SettingsCache> sSecureCaches
-            = new SparseArray<SettingsCache>();
-    private static final SettingsCache sGlobalCache = new SettingsCache(TABLE_GLOBAL);
-
-    // The count of how many known (handled by SettingsProvider)
-    // database mutations are currently being handled for this user.
-    // Used by file observers to not reload the database when it's ourselves
-    // modifying it.
-    private static final SparseArray<AtomicInteger> sKnownMutationsInFlight
-            = new SparseArray<AtomicInteger>();
-
-    // Each defined user has their own settings
-    protected final SparseArray<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
-
-    // Keep the list of managed profiles synced here
-    private List<UserInfo> mManagedProfiles = null;
-
-    // Over this size we don't reject loading or saving settings but
-    // we do consider them broken/malicious and don't keep them in
-    // memory at least:
-    private static final int MAX_CACHE_ENTRY_SIZE = 500;
-
-    private static final Bundle NULL_SETTING = Bundle.forPair("value", null);
-
-    // Used as a sentinel value in an instance equality test when we
-    // want to cache the existence of a key, but not store its value.
-    private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null);
-
-    private UserManager mUserManager;
-    private BackupManager mBackupManager;
-
-    /**
-     * Settings which need to be treated as global/shared in multi-user environments.
-     */
-    static final HashSet<String> sSecureGlobalKeys;
-    static final HashSet<String> sSystemGlobalKeys;
-
-    // Settings that cannot be modified if associated user restrictions are enabled.
-    static final Map<String, String> sRestrictedKeys;
-
-    private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
-
-    static final HashSet<String> sSecureCloneToManagedKeys;
-    static final HashSet<String> sSystemCloneToManagedKeys;
-
+    // The set of removed legacy tables.
+    private static final Set<String> REMOVED_LEGACY_TABLES = new ArraySet<>();
     static {
-        // Keys (name column) from the 'secure' table that are now in the owner user's 'global'
-        // table, shared across all users
-        // These must match Settings.Secure.MOVED_TO_GLOBAL
-        sSecureGlobalKeys = new HashSet<String>();
-        Settings.Secure.getMovedKeys(sSecureGlobalKeys);
+        REMOVED_LEGACY_TABLES.add(TABLE_FAVORITES);
+        REMOVED_LEGACY_TABLES.add(TABLE_OLD_FAVORITES);
+        REMOVED_LEGACY_TABLES.add(TABLE_BLUETOOTH_DEVICES);
+        REMOVED_LEGACY_TABLES.add(TABLE_BOOKMARKS);
+        REMOVED_LEGACY_TABLES.add(TABLE_ANDROID_METADATA);
+    }
 
-        // Keys from the 'system' table now moved to 'global'
-        // These must match Settings.System.MOVED_TO_GLOBAL
-        sSystemGlobalKeys = new HashSet<String>();
-        Settings.System.getNonLegacyMovedKeys(sSystemGlobalKeys);
+    private static final int MUTATION_OPERATION_INSERT = 1;
+    private static final int MUTATION_OPERATION_DELETE = 2;
+    private static final int MUTATION_OPERATION_UPDATE = 3;
 
-        sRestrictedKeys = new HashMap<String, String>();
-        sRestrictedKeys.put(Settings.Secure.LOCATION_MODE, UserManager.DISALLOW_SHARE_LOCATION);
-        sRestrictedKeys.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+    private static final String[] ALL_COLUMNS = new String[] {
+            Settings.NameValueTable._ID,
+            Settings.NameValueTable.NAME,
+            Settings.NameValueTable.VALUE
+    };
+
+    private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null);
+
+    // Per user settings that cannot be modified if associated user restrictions are enabled.
+    private static final Map<String, String> sSettingToUserRestrictionMap = new ArrayMap<>();
+    static {
+        sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_MODE,
                 UserManager.DISALLOW_SHARE_LOCATION);
-        sRestrictedKeys.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
+        sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                UserManager.DISALLOW_SHARE_LOCATION);
+        sSettingToUserRestrictionMap.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
                 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-        sRestrictedKeys.put(Settings.Global.ADB_ENABLED, UserManager.DISALLOW_DEBUGGING_FEATURES);
-        sRestrictedKeys.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
+        sSettingToUserRestrictionMap.put(Settings.Global.ADB_ENABLED,
+                UserManager.DISALLOW_DEBUGGING_FEATURES);
+        sSettingToUserRestrictionMap.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
                 UserManager.ENSURE_VERIFY_APPS);
-        sRestrictedKeys.put(Settings.Global.PREFERRED_NETWORK_MODE,
+        sSettingToUserRestrictionMap.put(Settings.Global.PREFERRED_NETWORK_MODE,
                 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-
-        sSecureCloneToManagedKeys = new HashSet<String>();
-        for (int i = 0; i < Settings.Secure.CLONE_TO_MANAGED_PROFILE.length; i++) {
-            sSecureCloneToManagedKeys.add(Settings.Secure.CLONE_TO_MANAGED_PROFILE[i]);
-        }
-        sSystemCloneToManagedKeys = new HashSet<String>();
-        for (int i = 0; i < Settings.System.CLONE_TO_MANAGED_PROFILE.length; i++) {
-            sSystemCloneToManagedKeys.add(Settings.System.CLONE_TO_MANAGED_PROFILE[i]);
-        }
     }
 
-    private boolean settingMovedToGlobal(final String name) {
-        return sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name);
+    // Per user secure settings that moved to the for all users global settings.
+    static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
+    static {
+        Settings.Secure.getMovedToGlobalSettings(sSecureMovedToGlobalSettings);
     }
 
-    /**
-     * Decode a content URL into the table, projection, and arguments
-     * used to access the corresponding database rows.
-     */
-    private static class SqlArguments {
-        public String table;
-        public final String where;
-        public final String[] args;
-
-        /** Operate on existing rows. */
-        SqlArguments(Uri url, String where, String[] args) {
-            if (url.getPathSegments().size() == 1) {
-                // of the form content://settings/secure, arbitrary where clause
-                this.table = url.getPathSegments().get(0);
-                if (!DatabaseHelper.isValidTable(this.table)) {
-                    throw new IllegalArgumentException("Bad root path: " + this.table);
-                }
-                this.where = where;
-                this.args = args;
-            } else if (url.getPathSegments().size() != 2) {
-                throw new IllegalArgumentException("Invalid URI: " + url);
-            } else if (!TextUtils.isEmpty(where)) {
-                throw new UnsupportedOperationException("WHERE clause not supported: " + url);
-            } else {
-                // of the form content://settings/secure/element_name, no where clause
-                this.table = url.getPathSegments().get(0);
-                if (!DatabaseHelper.isValidTable(this.table)) {
-                    throw new IllegalArgumentException("Bad root path: " + this.table);
-                }
-                if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table) ||
-                    TABLE_GLOBAL.equals(this.table)) {
-                    this.where = Settings.NameValueTable.NAME + "=?";
-                    final String name = url.getPathSegments().get(1);
-                    this.args = new String[] { name };
-                    // Rewrite the table for known-migrated names
-                    if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table)) {
-                        if (sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name)) {
-                            this.table = TABLE_GLOBAL;
-                        }
-                    }
-                } else {
-                    // of the form content://bookmarks/19
-                    this.where = "_id=" + ContentUris.parseId(url);
-                    this.args = null;
-                }
-            }
-        }
-
-        /** Insert new rows (no where clause allowed). */
-        SqlArguments(Uri url) {
-            if (url.getPathSegments().size() == 1) {
-                this.table = url.getPathSegments().get(0);
-                if (!DatabaseHelper.isValidTable(this.table)) {
-                    throw new IllegalArgumentException("Bad root path: " + this.table);
-                }
-                this.where = null;
-                this.args = null;
-            } else {
-                throw new IllegalArgumentException("Invalid URI: " + url);
-            }
-        }
+    // Per user system settings that moved to the for all users global settings.
+    static final Set<String> sSystemMovedToGlobalSettings = new ArraySet<>();
+    static {
+        Settings.System.getMovedToGlobalSettings(sSystemMovedToGlobalSettings);
     }
 
-    /**
-     * Get the content URI of a row added to a table.
-     * @param tableUri of the entire table
-     * @param values found in the row
-     * @param rowId of the row
-     * @return the content URI for this particular row
-     */
-    private Uri getUriFor(Uri tableUri, ContentValues values, long rowId) {
-        if (tableUri.getPathSegments().size() != 1) {
-            throw new IllegalArgumentException("Invalid URI: " + tableUri);
-        }
-        String table = tableUri.getPathSegments().get(0);
-        if (TABLE_SYSTEM.equals(table) ||
-                TABLE_SECURE.equals(table) ||
-                TABLE_GLOBAL.equals(table)) {
-            String name = values.getAsString(Settings.NameValueTable.NAME);
-            return Uri.withAppendedPath(tableUri, name);
-        } else {
-            return ContentUris.withAppendedId(tableUri, rowId);
-        }
+    // Per user system settings that moved to the per user secure settings.
+    static final Set<String> sSystemMovedToSecureSettings = new ArraySet<>();
+    static {
+        Settings.System.getMovedToSecureSettings(sSystemMovedToSecureSettings);
     }
 
-    /**
-     * Send a notification when a particular content URI changes.
-     * Modify the system property used to communicate the version of
-     * this table, for tables which have such a property.  (The Settings
-     * contract class uses these to provide client-side caches.)
-     * @param uri to send notifications for
-     */
-    private void sendNotify(Uri uri, int userHandle) {
-        // Update the system property *first*, so if someone is listening for
-        // a notification and then using the contract class to get their data,
-        // the system property will be updated and they'll get the new data.
-
-        boolean backedUpDataChanged = false;
-        String property = null, table = uri.getPathSegments().get(0);
-        final boolean isGlobal = table.equals(TABLE_GLOBAL);
-        if (table.equals(TABLE_SYSTEM)) {
-            property = Settings.System.SYS_PROP_SETTING_VERSION;
-            backedUpDataChanged = true;
-        } else if (table.equals(TABLE_SECURE)) {
-            property = Settings.Secure.SYS_PROP_SETTING_VERSION;
-            backedUpDataChanged = true;
-        } else if (isGlobal) {
-            property = Settings.Global.SYS_PROP_SETTING_VERSION;    // this one is global
-            backedUpDataChanged = true;
-        }
-
-        if (property != null) {
-            long version = SystemProperties.getLong(property, 0) + 1;
-            if (LOCAL_LOGV) Log.v(TAG, "property: " + property + "=" + version);
-            SystemProperties.set(property, Long.toString(version));
-        }
-
-        // Inform the backup manager about a data change
-        if (backedUpDataChanged) {
-            mBackupManager.dataChanged();
-        }
-        // Now send the notification through the content framework.
-
-        String notify = uri.getQueryParameter("notify");
-        if (notify == null || "true".equals(notify)) {
-            final int notifyTarget = isGlobal ? UserHandle.USER_ALL : userHandle;
-            final long oldId = Binder.clearCallingIdentity();
-            try {
-                getContext().getContentResolver().notifyChange(uri, null, true, notifyTarget);
-            } finally {
-                Binder.restoreCallingIdentity(oldId);
-            }
-            if (LOCAL_LOGV) Log.v(TAG, "notifying for " + notifyTarget + ": " + uri);
-        } else {
-            if (LOCAL_LOGV) Log.v(TAG, "notification suppressed: " + uri);
-        }
+    // Per all users global settings that moved to the per user secure settings.
+    static final Set<String> sGlobalMovedToSecureSettings = new ArraySet<>();
+    static {
+        Settings.Global.getMovedToSecureSettings(sGlobalMovedToSecureSettings);
     }
 
-    /**
-     * Make sure the caller has permission to write this data.
-     * @param args supplied by the caller
-     * @throws SecurityException if the caller is forbidden to write.
-     */
-    private void checkWritePermissions(SqlArguments args) {
-        if ((TABLE_SECURE.equals(args.table) || TABLE_GLOBAL.equals(args.table)) &&
-            getContext().checkCallingOrSelfPermission(
-                    android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
-            PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(
-                    String.format("Permission denial: writing to secure settings requires %1$s",
-                                  android.Manifest.permission.WRITE_SECURE_SETTINGS));
-        }
+    // Per user secure settings that are cloned for the managed profiles of the user.
+    private static final Set<String> sSecureCloneToManagedSettings = new ArraySet<>();
+    static {
+        Settings.Secure.getCloneToManagedProfileSettings(sSecureCloneToManagedSettings);
     }
 
-    private void checkUserRestrictions(String setting, int userId) {
-        String userRestriction = sRestrictedKeys.get(setting);
-        if (!TextUtils.isEmpty(userRestriction)
-            && mUserManager.hasUserRestriction(userRestriction, new UserHandle(userId))) {
-            throw new SecurityException(
-                    "Permission denial: user is restricted from changing this setting.");
-        }
+    // Per user system settings that are cloned for the managed profiles of the user.
+    private static final Set<String> sSystemCloneToManagedSettings = new ArraySet<>();
+    static {
+        Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings);
     }
 
-    // FileObserver for external modifications to the database file.
-    // Note that this is for platform developers only with
-    // userdebug/eng builds who should be able to tinker with the
-    // sqlite database out from under the SettingsProvider, which is
-    // normally the exclusive owner of the database.  But we keep this
-    // enabled all the time to minimize development-vs-user
-    // differences in testing.
-    private static SparseArray<SettingsFileObserver> sObserverInstances
-            = new SparseArray<SettingsFileObserver>();
-    private class SettingsFileObserver extends FileObserver {
-        private final AtomicBoolean mIsDirty = new AtomicBoolean(false);
-        private final int mUserHandle;
-        private final String mPath;
+    private final Object mLock = new Object();
 
-        public SettingsFileObserver(int userHandle, String path) {
-            super(path, FileObserver.CLOSE_WRITE |
-                  FileObserver.CREATE | FileObserver.DELETE |
-                  FileObserver.MOVED_TO | FileObserver.MODIFY);
-            mUserHandle = userHandle;
-            mPath = path;
-        }
+    @GuardedBy("mLock")
+    private SettingsRegistry mSettingsRegistry;
 
-        public void onEvent(int event, String path) {
-            final AtomicInteger mutationCount;
-            synchronized (SettingsProvider.this) {
-                mutationCount = sKnownMutationsInFlight.get(mUserHandle);
-            }
-            if (mutationCount != null && mutationCount.get() > 0) {
-                // our own modification.
-                return;
-            }
-            Log.d(TAG, "User " + mUserHandle + " external modification to " + mPath
-                    + "; event=" + event);
-            if (!mIsDirty.compareAndSet(false, true)) {
-                // already handled. (we get a few update events
-                // during an sqlite write)
-                return;
-            }
-            Log.d(TAG, "User " + mUserHandle + " updating our caches for " + mPath);
-            fullyPopulateCaches(mUserHandle);
-            mIsDirty.set(false);
-        }
-    }
+    @GuardedBy("mLock")
+    private UserManager mUserManager;
+
+    @GuardedBy("mLock")
+    private AppOpsManager mAppOpsManager;
+
+    @GuardedBy("mLock")
+    private PackageManager mPackageManager;
 
     @Override
     public boolean onCreate() {
-        mBackupManager = new BackupManager(getContext());
-        mUserManager = UserManager.get(getContext());
-
-        setAppOps(AppOpsManager.OP_NONE, AppOpsManager.OP_WRITE_SETTINGS);
-        establishDbTracking(UserHandle.USER_OWNER);
-
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        userFilter.addAction(Intent.ACTION_USER_ADDED);
-        getContext().registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_OWNER);
-                if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
-                    onUserRemoved(userHandle);
-                } else if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
-                    onProfilesChanged();
-                }
-            }
-        }, userFilter);
-
-        onProfilesChanged();
-
+        synchronized (mLock) {
+            mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+            mAppOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+            mPackageManager = getContext().getPackageManager();
+            mSettingsRegistry = new SettingsRegistry();
+        }
+        registerBroadcastReceivers();
         return true;
     }
 
-    void onUserRemoved(int userHandle) {
-        synchronized (this) {
-            // the db file itself will be deleted automatically, but we need to tear down
-            // our caches and other internal bookkeeping.
-            FileObserver observer = sObserverInstances.get(userHandle);
-            if (observer != null) {
-                observer.stopWatching();
-                sObserverInstances.delete(userHandle);
-            }
-
-            mOpenHelpers.delete(userHandle);
-            sSystemCaches.delete(userHandle);
-            sSecureCaches.delete(userHandle);
-            sKnownMutationsInFlight.delete(userHandle);
-            onProfilesChanged();
-        }
-    }
-
-    /**
-     * Updates the list of managed profiles. It assumes that only the primary user
-     * can have managed profiles. Modify this code if that changes in the future.
-     */
-    void onProfilesChanged() {
-        synchronized (this) {
-            mManagedProfiles = mUserManager.getProfiles(UserHandle.USER_OWNER);
-            if (mManagedProfiles != null) {
-                // Remove the primary user from the list
-                for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                    if (mManagedProfiles.get(i).id == UserHandle.USER_OWNER) {
-                        mManagedProfiles.remove(i);
-                    }
-                }
-                // If there are no managed profiles, reset the variable
-                if (mManagedProfiles.size() == 0) {
-                    mManagedProfiles = null;
-                }
-            }
-            if (LOCAL_LOGV) {
-                Slog.d(TAG, "Managed Profiles = " + mManagedProfiles);
-            }
-        }
-    }
-
-    private void establishDbTracking(int userHandle) {
-        if (LOCAL_LOGV) {
-            Slog.i(TAG, "Installing settings db helper and caches for user " + userHandle);
-        }
-
-        DatabaseHelper dbhelper;
-
-        synchronized (this) {
-            dbhelper = mOpenHelpers.get(userHandle);
-            if (dbhelper == null) {
-                dbhelper = new DatabaseHelper(getContext(), userHandle);
-                mOpenHelpers.append(userHandle, dbhelper);
-
-                sSystemCaches.append(userHandle, new SettingsCache(TABLE_SYSTEM));
-                sSecureCaches.append(userHandle, new SettingsCache(TABLE_SECURE));
-                sKnownMutationsInFlight.append(userHandle, new AtomicInteger(0));
-            }
-        }
-
-        // Initialization of the db *outside* the locks.  It's possible that racing
-        // threads might wind up here, the second having read the cache entries
-        // written by the first, but that's benign: the SQLite helper implementation
-        // manages concurrency itself, and it's important that we not run the db
-        // initialization with any of our own locks held, so we're fine.
-        SQLiteDatabase db = dbhelper.getWritableDatabase();
-
-        // Watch for external modifications to the database files,
-        // keeping our caches in sync.  We synchronize the observer set
-        // separately, and of course it has to run after the db file
-        // itself was set up by the DatabaseHelper.
-        synchronized (sObserverInstances) {
-            if (sObserverInstances.get(userHandle) == null) {
-                SettingsFileObserver observer = new SettingsFileObserver(userHandle, db.getPath());
-                sObserverInstances.append(userHandle, observer);
-                observer.startWatching();
-            }
-        }
-
-        ensureAndroidIdIsSet(userHandle);
-
-        startAsyncCachePopulation(userHandle);
-    }
-
-    class CachePrefetchThread extends Thread {
-        private int mUserHandle;
-
-        CachePrefetchThread(int userHandle) {
-            super("populate-settings-caches");
-            mUserHandle = userHandle;
-        }
-
-        @Override
-        public void run() {
-            fullyPopulateCaches(mUserHandle);
-        }
-    }
-
-    private void startAsyncCachePopulation(int userHandle) {
-        new CachePrefetchThread(userHandle).start();
-    }
-
-    private void fullyPopulateCaches(final int userHandle) {
-        DatabaseHelper dbHelper;
-        synchronized (this) {
-            dbHelper = mOpenHelpers.get(userHandle);
-        }
-        if (dbHelper == null) {
-            // User is gone.
-            return;
-        }
-        // Only populate the globals cache once, for the owning user
-        if (userHandle == UserHandle.USER_OWNER) {
-            fullyPopulateCache(dbHelper, TABLE_GLOBAL, sGlobalCache);
-        }
-        fullyPopulateCache(dbHelper, TABLE_SECURE, sSecureCaches.get(userHandle));
-        fullyPopulateCache(dbHelper, TABLE_SYSTEM, sSystemCaches.get(userHandle));
-    }
-
-    // Slurp all values (if sane in number & size) into cache.
-    private void fullyPopulateCache(DatabaseHelper dbHelper, String table, SettingsCache cache) {
-        SQLiteDatabase db = dbHelper.getReadableDatabase();
-        Cursor c = db.query(
-            table,
-            new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE },
-            null, null, null, null, null,
-            "" + (MAX_CACHE_ENTRIES + 1) /* limit */);
-        try {
-            synchronized (cache) {
-                cache.evictAll();
-                cache.setFullyMatchesDisk(true);  // optimistic
-                int rows = 0;
-                while (c.moveToNext()) {
-                    rows++;
-                    String name = c.getString(0);
-                    String value = c.getString(1);
-                    cache.populate(name, value);
-                }
-                if (rows > MAX_CACHE_ENTRIES) {
-                    // Somewhat redundant, as removeEldestEntry() will
-                    // have already done this, but to be explicit:
-                    cache.setFullyMatchesDisk(false);
-                    Log.d(TAG, "row count exceeds max cache entries for table " + table);
-                }
-                if (LOCAL_LOGV) Log.d(TAG, "cache for settings table '" + table
-                        + "' rows=" + rows + "; fullycached=" + cache.fullyMatchesDisk());
-            }
-        } finally {
-            c.close();
-        }
-    }
-
-    private boolean ensureAndroidIdIsSet(int userHandle) {
-        final Cursor c = queryForUser(Settings.Secure.CONTENT_URI,
-                new String[] { Settings.NameValueTable.VALUE },
-                Settings.NameValueTable.NAME + "=?",
-                new String[] { Settings.Secure.ANDROID_ID }, null,
-                userHandle);
-        try {
-            final String value = c.moveToNext() ? c.getString(0) : null;
-            if (value == null) {
-                // sanity-check the user before touching the db
-                final UserInfo user = mUserManager.getUserInfo(userHandle);
-                if (user == null) {
-                    // can happen due to races when deleting users; treat as benign
-                    return false;
+    @Override
+    public Bundle call(String method, String name, Bundle args) {
+        synchronized (mLock) {
+            final int requestingUserId = getRequestingUserId(args);
+            switch (method) {
+                case Settings.CALL_METHOD_GET_GLOBAL: {
+                    Setting setting = getGlobalSettingLocked(name);
+                    return packageValueForCallResult(setting);
                 }
 
-                final SecureRandom random = new SecureRandom();
-                final String newAndroidIdValue = Long.toHexString(random.nextLong());
-                final ContentValues values = new ContentValues();
-                values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID);
-                values.put(Settings.NameValueTable.VALUE, newAndroidIdValue);
-                final Uri uri = insertForUser(Settings.Secure.CONTENT_URI, values, userHandle);
-                if (uri == null) {
-                    Slog.e(TAG, "Unable to generate new ANDROID_ID for user " + userHandle);
-                    return false;
+                case Settings.CALL_METHOD_GET_SECURE: {
+                    Setting setting = getSecureSettingLocked(name, requestingUserId);
+                    return packageValueForCallResult(setting);
                 }
-                Slog.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue
-                        + "] for user " + userHandle);
-                // Write a dropbox entry if it's a restricted profile
-                if (user.isRestricted()) {
-                    DropBoxManager dbm = (DropBoxManager)
-                            getContext().getSystemService(Context.DROPBOX_SERVICE);
-                    if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
-                        dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
-                                + ",restricted_profile_ssaid,"
-                                + newAndroidIdValue + "\n");
-                    }
+
+                case Settings.CALL_METHOD_GET_SYSTEM: {
+                    Setting setting = getSystemSettingLocked(name, requestingUserId);
+                    return packageValueForCallResult(setting);
                 }
-            }
-            return true;
-        } finally {
-            c.close();
-        }
-    }
 
-    // Lazy-initialize the settings caches for non-primary users
-    private SettingsCache getOrConstructCache(int callingUser, SparseArray<SettingsCache> which) {
-        getOrEstablishDatabase(callingUser); // ignore return value; we don't need it
-        return which.get(callingUser);
-    }
+                case Settings.CALL_METHOD_PUT_GLOBAL: {
+                    String value = getSettingValue(args);
+                    insertGlobalSettingLocked(name, value, requestingUserId);
+                } break;
 
-    // Lazy initialize the database helper and caches for this user, if necessary
-    private DatabaseHelper getOrEstablishDatabase(int callingUser) {
-        if (callingUser >= Process.SYSTEM_UID) {
-            if (USER_CHECK_THROWS) {
-                throw new IllegalArgumentException("Uid rather than user handle: " + callingUser);
-            } else {
-                Slog.wtf(TAG, "establish db for uid rather than user: " + callingUser);
-            }
-        }
+                case Settings.CALL_METHOD_PUT_SECURE: {
+                    String value = getSettingValue(args);
+                    insertSecureSettingLocked(name, value, requestingUserId);
+                } break;
 
-        long oldId = Binder.clearCallingIdentity();
-        try {
-            DatabaseHelper dbHelper;
-            synchronized (this) {
-                dbHelper = mOpenHelpers.get(callingUser);
-            }
-            if (null == dbHelper) {
-                establishDbTracking(callingUser);
-                synchronized (this) {
-                    dbHelper = mOpenHelpers.get(callingUser);
-                }
-            }
-            return dbHelper;
-        } finally {
-            Binder.restoreCallingIdentity(oldId);
-        }
-    }
+                case Settings.CALL_METHOD_PUT_SYSTEM: {
+                    String value = getSettingValue(args);
+                    insertSystemSettingLocked(name, value, requestingUserId);
+                } break;
 
-    public SettingsCache cacheForTable(final int callingUser, String tableName) {
-        if (TABLE_SYSTEM.equals(tableName)) {
-            return getOrConstructCache(callingUser, sSystemCaches);
-        }
-        if (TABLE_SECURE.equals(tableName)) {
-            return getOrConstructCache(callingUser, sSecureCaches);
-        }
-        if (TABLE_GLOBAL.equals(tableName)) {
-            return sGlobalCache;
+                default: {
+                    Slog.w(LOG_TAG, "call() with invalid method: " + method);
+                } break;
+            }
         }
         return null;
     }
 
-    /**
-     * Used for wiping a whole cache on deletes when we're not
-     * sure what exactly was deleted or changed.
-     */
-    public void invalidateCache(final int callingUser, String tableName) {
-        SettingsCache cache = cacheForTable(callingUser, tableName);
-        if (cache == null) {
-            return;
-        }
-        synchronized (cache) {
-            cache.evictAll();
-            cache.mCacheFullyMatchesDisk = false;
-        }
-    }
-
-    /**
-     * Checks if the calling user is a managed profile of the primary user.
-     * Currently only the primary user (USER_OWNER) can have managed profiles.
-     * @param callingUser the user trying to read/write settings
-     * @return true if it is a managed profile of the primary user
-     */
-    private boolean isManagedProfile(int callingUser) {
-        synchronized (this) {
-            if (mManagedProfiles == null) return false;
-            for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                if (mManagedProfiles.get(i).id == callingUser) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Fast path that avoids the use of chatty remoted Cursors.
-     */
     @Override
-    public Bundle call(String method, String request, Bundle args) {
-        int callingUser = UserHandle.getCallingUserId();
-        if (args != null) {
-            int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser);
-            if (reqUser != callingUser) {
-                callingUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                        Binder.getCallingUid(), reqUser, false, true,
-                        "get/set setting for user", null);
-                if (LOCAL_LOGV) Slog.v(TAG, "   access setting for user " + callingUser);
-            }
-        }
-
-        // Note: we assume that get/put operations for moved-to-global names have already
-        // been directed to the new location on the caller side (otherwise we'd fix them
-        // up here).
-        DatabaseHelper dbHelper;
-        SettingsCache cache;
-
-        // Get methods
-        if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
-            if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
-            // Check if this request should be (re)directed to the primary user's db
-            if (callingUser != UserHandle.USER_OWNER
-                    && shouldShadowParentProfile(callingUser, sSystemCloneToManagedKeys, request)) {
-                callingUser = UserHandle.USER_OWNER;
-            }
-            dbHelper = getOrEstablishDatabase(callingUser);
-            cache = sSystemCaches.get(callingUser);
-            return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
-        }
-        if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
-            if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
-            // Check if this is a setting to be copied from the primary user
-            if (shouldShadowParentProfile(callingUser, sSecureCloneToManagedKeys, request)) {
-                // If the request if for location providers and there's a restriction, return none
-                if (Secure.LOCATION_PROVIDERS_ALLOWED.equals(request)
-                        && mUserManager.hasUserRestriction(
-                                UserManager.DISALLOW_SHARE_LOCATION, new UserHandle(callingUser))) {
-                    return sSecureCaches.get(callingUser).putIfAbsent(request, "");
-                }
-                callingUser = UserHandle.USER_OWNER;
-            }
-            dbHelper = getOrEstablishDatabase(callingUser);
-            cache = sSecureCaches.get(callingUser);
-            return lookupValue(dbHelper, TABLE_SECURE, cache, request);
-        }
-        if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
-            if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
-            // fast path: owner db & cache are immutable after onCreate() so we need not
-            // guard on the attempt to look them up
-            return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
-                    sGlobalCache, request);
-        }
-
-        // Put methods - new value is in the args bundle under the key named by
-        // the Settings.NameValueTable.VALUE static.
-        final String newValue = (args == null)
-                ? null : args.getString(Settings.NameValueTable.VALUE);
-
-        // Framework can't do automatic permission checking for calls, so we need
-        // to do it here.
-        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(
-                    String.format("Permission denial: writing to settings requires %1$s",
-                                  android.Manifest.permission.WRITE_SETTINGS));
-        }
-
-        // Also need to take care of app op.
-        if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SETTINGS, Binder.getCallingUid(),
-                getCallingPackage()) != AppOpsManager.MODE_ALLOWED) {
-            return null;
-        }
-
-        final ContentValues values = new ContentValues();
-        values.put(Settings.NameValueTable.NAME, request);
-        values.put(Settings.NameValueTable.VALUE, newValue);
-        if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
-            if (LOCAL_LOGV) {
-                Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for "
-                        + callingUser);
-            }
-            // Extra check for USER_OWNER to optimize for the 99%
-            if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
-                    sSystemCloneToManagedKeys, request)) {
-                // Don't write these settings, as they are cloned from the parent profile
-                return null;
-            }
-            insertForUser(Settings.System.CONTENT_URI, values, callingUser);
-            // Clone the settings to the managed profiles so that notifications can be sent out
-            if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
-                    && sSystemCloneToManagedKeys.contains(request)) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                        if (LOCAL_LOGV) {
-                            Slog.v(TAG, "putting to additional user "
-                                    + mManagedProfiles.get(i).id);
-                        }
-                        insertForUser(Settings.System.CONTENT_URI, values,
-                                mManagedProfiles.get(i).id);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
-            if (LOCAL_LOGV) {
-                Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for "
-                        + callingUser);
-            }
-            // Extra check for USER_OWNER to optimize for the 99%
-            if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
-                    sSecureCloneToManagedKeys, request)) {
-                // Don't write these settings, as they are cloned from the parent profile
-                return null;
-            }
-            insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
-            // Clone the settings to the managed profiles so that notifications can be sent out
-            if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
-                    && sSecureCloneToManagedKeys.contains(request)) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                        if (LOCAL_LOGV) {
-                            Slog.v(TAG, "putting to additional user "
-                                    + mManagedProfiles.get(i).id);
-                        }
-                        try {
-                            insertForUser(Settings.Secure.CONTENT_URI, values,
-                                    mManagedProfiles.get(i).id);
-                        } catch (SecurityException e) {
-                            // Temporary fix, see b/17450158
-                            Slog.w(TAG, "Cannot clone request '" + request + "' with value '"
-                                    + newValue + "' to managed profile (id "
-                                    + mManagedProfiles.get(i).id + ")", e);
-                        }
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
-            if (LOCAL_LOGV) {
-                Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for "
-                        + callingUser);
-            }
-            insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
-        } else {
-            Slog.w(TAG, "call() with invalid method: " + method);
-        }
-
-        return null;
-    }
-
-    /**
-     * Check if the user is a managed profile and name is one of the settings to be cloned
-     * from the parent profile.
-     */
-    private boolean shouldShadowParentProfile(int userId, HashSet<String> keys, String name) {
-        return isManagedProfile(userId) && keys.contains(name);
-    }
-
-    // Looks up value 'key' in 'table' and returns either a single-pair Bundle,
-    // possibly with a null value, or null on failure.
-    private Bundle lookupValue(DatabaseHelper dbHelper, String table,
-            final SettingsCache cache, String key) {
-        if (cache == null) {
-           Slog.e(TAG, "cache is null for user " + UserHandle.getCallingUserId() + " : key=" + key);
-           return null;
-        }
-        synchronized (cache) {
-            Bundle value = cache.get(key);
-            if (value != null) {
-                if (value != TOO_LARGE_TO_CACHE_MARKER) {
-                    return value;
-                }
-                // else we fall through and read the value from disk
-            } else if (cache.fullyMatchesDisk()) {
-                // Fast path (very common).  Don't even try touch disk
-                // if we know we've slurped it all in.  Trying to
-                // touch the disk would mean waiting for yaffs2 to
-                // give us access, which could takes hundreds of
-                // milliseconds.  And we're very likely being called
-                // from somebody's UI thread...
-                return NULL_SETTING;
-            }
-        }
-
-        SQLiteDatabase db = dbHelper.getReadableDatabase();
-        Cursor cursor = null;
-        try {
-            cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key},
-                              null, null, null, null);
-            if (cursor != null && cursor.getCount() == 1) {
-                cursor.moveToFirst();
-                return cache.putIfAbsent(key, cursor.getString(0));
-            }
-        } catch (SQLiteException e) {
-            Log.w(TAG, "settings lookup error", e);
-            return null;
-        } finally {
-            if (cursor != null) cursor.close();
-        }
-        cache.putIfAbsent(key, null);
-        return NULL_SETTING;
-    }
-
-    @Override
-    public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
-        return queryForUser(url, select, where, whereArgs, sort, UserHandle.getCallingUserId());
-    }
-
-    private Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
-            String sort, int forUser) {
-        if (LOCAL_LOGV) Slog.v(TAG, "query(" + url + ") for user " + forUser);
-        SqlArguments args = new SqlArguments(url, where, whereArgs);
-        DatabaseHelper dbH;
-        dbH = getOrEstablishDatabase(
-                TABLE_GLOBAL.equals(args.table) ? UserHandle.USER_OWNER : forUser);
-        SQLiteDatabase db = dbH.getReadableDatabase();
-
-        // The favorites table was moved from this provider to a provider inside Home
-        // Home still need to query this table to upgrade from pre-cupcake builds
-        // However, a cupcake+ build with no data does not contain this table which will
-        // cause an exception in the SQL stack. The following line is a special case to
-        // let the caller of the query have a chance to recover and avoid the exception
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return null;
-        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
-            args.table = TABLE_FAVORITES;
-            Cursor cursor = db.rawQuery("PRAGMA table_info(favorites);", null);
-            if (cursor != null) {
-                boolean exists = cursor.getCount() > 0;
-                cursor.close();
-                if (!exists) return null;
-            } else {
-                return null;
-            }
-        }
-
-        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
-        qb.setTables(args.table);
-
-        Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
-        // the default Cursor interface does not support per-user observation
-        try {
-            AbstractCursor c = (AbstractCursor) ret;
-            c.setNotificationUri(getContext().getContentResolver(), url, forUser);
-        } catch (ClassCastException e) {
-            // details of the concrete Cursor implementation have changed and this code has
-            // not been updated to match -- complain and fail hard.
-            Log.wtf(TAG, "Incompatible cursor derivation!");
-            throw e;
-        }
-        return ret;
-    }
-
-    @Override
-    public String getType(Uri url) {
-        // If SqlArguments supplies a where clause, then it must be an item
-        // (because we aren't supplying our own where clause).
-        SqlArguments args = new SqlArguments(url, null, null);
-        if (TextUtils.isEmpty(args.where)) {
+    public String getType(Uri uri) {
+        Arguments args = new Arguments(uri, null, null, true);
+        if (TextUtils.isEmpty(args.name)) {
             return "vnd.android.cursor.dir/" + args.table;
         } else {
-            return "vnd.android.cursor.item/" + args.table;
+                return "vnd.android.cursor.item/" + args.table;
         }
     }
 
     @Override
-    public int bulkInsert(Uri uri, ContentValues[] values) {
-        final int callingUser = UserHandle.getCallingUserId();
-        if (LOCAL_LOGV) Slog.v(TAG, "bulkInsert() for user " + callingUser);
-        SqlArguments args = new SqlArguments(uri);
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return 0;
-        }
-        checkWritePermissions(args);
-        SettingsCache cache = cacheForTable(callingUser, args.table);
-
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
-        }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
-        }
-        DatabaseHelper dbH = getOrEstablishDatabase(
-                TABLE_GLOBAL.equals(args.table) ? UserHandle.USER_OWNER : callingUser);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        db.beginTransaction();
-        try {
-            int numValues = values.length;
-            for (int i = 0; i < numValues; i++) {
-                checkUserRestrictions(values[i].getAsString(Settings.Secure.NAME), callingUser);
-                if (db.insert(args.table, null, values[i]) < 0) return 0;
-                SettingsCache.populate(cache, values[i]);
-                if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + values[i]);
-            }
-            db.setTransactionSuccessful();
-        } finally {
-            db.endTransaction();
-            if (mutationCount != null) {
-                mutationCount.decrementAndGet();
-            }
+    public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs,
+            String order) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "query() for user: " + UserHandle.getCallingUserId());
         }
 
-        sendNotify(uri, callingUser);
-        return values.length;
-    }
+        Arguments args = new Arguments(uri, where, whereArgs, true);
+        String[] normalizedProjection = normalizeProjection(projection);
 
-    /*
-     * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
-     * This setting contains a list of the currently enabled location providers.
-     * But helper functions in android.providers.Settings can enable or disable
-     * a single provider by using a "+" or "-" prefix before the provider name.
-     *
-     * @returns whether the database needs to be updated or not, also modifying
-     *     'initialValues' if needed.
-     */
-    private boolean parseProviderList(Uri url, ContentValues initialValues, int desiredUser) {
-        String value = initialValues.getAsString(Settings.Secure.VALUE);
-        String newProviders = null;
-        if (value != null && value.length() > 1) {
-            char prefix = value.charAt(0);
-            if (prefix == '+' || prefix == '-') {
-                // skip prefix
-                value = value.substring(1);
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+            return new MatrixCursor(normalizedProjection, 0);
+        }
 
-                // read list of enabled providers into "providers"
-                String providers = "";
-                String[] columns = {Settings.Secure.VALUE};
-                String where = Settings.Secure.NAME + "=\'" + Settings.Secure.LOCATION_PROVIDERS_ALLOWED + "\'";
-                Cursor cursor = queryForUser(url, columns, where, null, null, desiredUser);
-                if (cursor != null && cursor.getCount() == 1) {
-                    try {
-                        cursor.moveToFirst();
-                        providers = cursor.getString(0);
-                    } finally {
-                        cursor.close();
-                    }
-                }
-
-                int index = providers.indexOf(value);
-                int end = index + value.length();
-                // check for commas to avoid matching on partial string
-                if (index > 0 && providers.charAt(index - 1) != ',') index = -1;
-                if (end < providers.length() && providers.charAt(end) != ',') index = -1;
-
-                if (prefix == '+' && index < 0) {
-                    // append the provider to the list if not present
-                    if (providers.length() == 0) {
-                        newProviders = value;
+        synchronized (mLock) {
+            switch (args.table) {
+                case TABLE_GLOBAL: {
+                    if (args.name != null) {
+                        Setting setting = getGlobalSettingLocked(args.name);
+                        return packageSettingForQuery(setting, normalizedProjection);
                     } else {
-                        newProviders = providers + ',' + value;
+                        return getAllGlobalSettingsLocked(projection);
                     }
-                } else if (prefix == '-' && index >= 0) {
-                    // remove the provider from the list if present
-                    // remove leading or trailing comma
-                    if (index > 0) {
-                        index--;
-                    } else if (end < providers.length()) {
-                        end++;
-                    }
-
-                    newProviders = providers.substring(0, index);
-                    if (end < providers.length()) {
-                        newProviders += providers.substring(end);
-                    }
-                } else {
-                    // nothing changed, so no need to update the database
-                    return false;
                 }
 
-                if (newProviders != null) {
-                    initialValues.put(Settings.Secure.VALUE, newProviders);
+                case TABLE_SECURE: {
+                    final int userId = UserHandle.getCallingUserId();
+                    if (args.name != null) {
+                        Setting setting = getSecureSettingLocked(args.name, userId);
+                        return packageSettingForQuery(setting, normalizedProjection);
+                    } else {
+                        return getAllSecureSettingsLocked(userId, projection);
+                    }
+                }
+
+                case TABLE_SYSTEM: {
+                    final int userId = UserHandle.getCallingUserId();
+                    if (args.name != null) {
+                        Setting setting = getSystemSettingLocked(args.name, userId);
+                        return packageSettingForQuery(setting, normalizedProjection);
+                    } else {
+                        return getAllSystemSettingsLocked(userId, projection);
+                    }
+                }
+
+                default: {
+                    throw new IllegalArgumentException("Invalid Uri path:" + uri);
                 }
             }
         }
-
-        return true;
     }
 
     @Override
-    public Uri insert(Uri url, ContentValues initialValues) {
-        return insertForUser(url, initialValues, UserHandle.getCallingUserId());
-    }
-
-    // Settings.put*ForUser() always winds up here, so this is where we apply
-    // policy around permission to write settings for other users.
-    private Uri insertForUser(Uri url, ContentValues initialValues, int desiredUserHandle) {
-        final int callingUser = UserHandle.getCallingUserId();
-        if (callingUser != desiredUserHandle) {
-            getContext().enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "Not permitted to access settings for other users");
+    public Uri insert(Uri uri, ContentValues values) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insert() for user: " + UserHandle.getCallingUserId());
         }
 
-        if (LOCAL_LOGV) Slog.v(TAG, "insert(" + url + ") for user " + desiredUserHandle
-                + " by " + callingUser);
+        String table = getValidTableOrThrow(uri);
 
-        SqlArguments args = new SqlArguments(url);
-        if (TABLE_FAVORITES.equals(args.table)) {
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(table)) {
             return null;
         }
 
-        // Special case LOCATION_PROVIDERS_ALLOWED.
-        // Support enabling/disabling a single provider (using "+" or "-" prefix)
-        String name = initialValues.getAsString(Settings.Secure.NAME);
-        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
-            if (!parseProviderList(url, initialValues, desiredUserHandle)) return null;
+        String name = values.getAsString(Settings.Secure.NAME);
+        if (TextUtils.isEmpty(name)) {
+            return null;
         }
 
-        // If this is an insert() of a key that has been migrated to the global store,
-        // redirect the operation to that store
-        if (name != null) {
-            if (sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name)) {
-                if (!TABLE_GLOBAL.equals(args.table)) {
-                    if (LOCAL_LOGV) Slog.i(TAG, "Rewrite of insert() of now-global key " + name);
+        String value = values.getAsString(Settings.Secure.VALUE);
+
+        synchronized (mLock) {
+            switch (table) {
+                case TABLE_GLOBAL: {
+                    if (insertGlobalSettingLocked(name, value, UserHandle.getCallingUserId())) {
+                        return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
+                    }
+                } break;
+
+                case TABLE_SECURE: {
+                    if (insertSecureSettingLocked(name, value, UserHandle.getCallingUserId())) {
+                        return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
+                    }
+                } break;
+
+                case TABLE_SYSTEM: {
+                    if (insertSystemSettingLocked(name, value, UserHandle.getCallingUserId())) {
+                        return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
+                    }
+                } break;
+
+                default: {
+                    throw new IllegalArgumentException("Bad Uri path:" + uri);
                 }
-                args.table = TABLE_GLOBAL;  // next condition will rewrite the user handle
             }
         }
 
-        // Check write permissions only after determining which table the insert will touch
-        checkWritePermissions(args);
-
-        checkUserRestrictions(name, desiredUserHandle);
-
-        // The global table is stored under the owner, always
-        if (TABLE_GLOBAL.equals(args.table)) {
-            desiredUserHandle = UserHandle.USER_OWNER;
-        }
-
-        SettingsCache cache = cacheForTable(desiredUserHandle, args.table);
-        String value = initialValues.getAsString(Settings.NameValueTable.VALUE);
-        if (SettingsCache.isRedundantSetValue(cache, name, value)) {
-            return Uri.withAppendedPath(url, name);
-        }
-
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
-        }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
-        }
-        DatabaseHelper dbH = getOrEstablishDatabase(desiredUserHandle);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        final long rowId = db.insert(args.table, null, initialValues);
-        if (mutationCount != null) {
-            mutationCount.decrementAndGet();
-        }
-        if (rowId <= 0) return null;
-
-        SettingsCache.populate(cache, initialValues);  // before we notify
-
-        if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues
-                + " for user " + desiredUserHandle);
-        // Note that we use the original url here, not the potentially-rewritten table name
-        url = getUriFor(url, initialValues, rowId);
-        sendNotify(url, desiredUserHandle);
-        return url;
+        return null;
     }
 
     @Override
-    public int delete(Uri url, String where, String[] whereArgs) {
-        int callingUser = UserHandle.getCallingUserId();
-        if (LOCAL_LOGV) Slog.v(TAG, "delete() for user " + callingUser);
-        SqlArguments args = new SqlArguments(url, where, whereArgs);
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return 0;
-        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
-            args.table = TABLE_FAVORITES;
-        } else if (TABLE_GLOBAL.equals(args.table)) {
-            callingUser = UserHandle.USER_OWNER;
+    public int bulkInsert(Uri uri, ContentValues[] allValues) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "bulkInsert() for user: " + UserHandle.getCallingUserId());
         }
-        checkWritePermissions(args);
 
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
+        int insertionCount = 0;
+        final int valuesCount = allValues.length;
+        for (int i = 0; i < valuesCount; i++) {
+            ContentValues values = allValues[i];
+            if (insert(uri, values) != null) {
+                insertionCount++;
+            }
         }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
-        }
-        DatabaseHelper dbH = getOrEstablishDatabase(callingUser);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        int count = db.delete(args.table, args.where, args.args);
-        if (mutationCount != null) {
-            mutationCount.decrementAndGet();
-        }
-        if (count > 0) {
-            invalidateCache(callingUser, args.table);  // before we notify
-            sendNotify(url, callingUser);
-        }
-        startAsyncCachePopulation(callingUser);
-        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
-        return count;
+
+        return insertionCount;
     }
 
     @Override
-    public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
-        // NOTE: update() is never called by the front-end Settings API, and updates that
-        // wind up affecting rows in Secure that are globally shared will not have the
-        // intended effect (the update will be invisible to the rest of the system).
-        // This should have no practical effect, since writes to the Secure db can only
-        // be done by system code, and that code should be using the correct API up front.
-        int callingUser = UserHandle.getCallingUserId();
-        if (LOCAL_LOGV) Slog.v(TAG, "update() for user " + callingUser);
-        SqlArguments args = new SqlArguments(url, where, whereArgs);
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return 0;
-        } else if (TABLE_GLOBAL.equals(args.table)) {
-            callingUser = UserHandle.USER_OWNER;
+    public int delete(Uri uri, String where, String[] whereArgs) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "delete() for user: " + UserHandle.getCallingUserId());
         }
-        checkWritePermissions(args);
-        checkUserRestrictions(initialValues.getAsString(Settings.Secure.NAME), callingUser);
 
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
+        Arguments args = new Arguments(uri, where, whereArgs, false);
+
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+            return 0;
         }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
+
+        if (TextUtils.isEmpty(args.name)) {
+            return 0;
         }
-        DatabaseHelper dbH = getOrEstablishDatabase(callingUser);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        int count = db.update(args.table, initialValues, args.where, args.args);
-        if (mutationCount != null) {
-            mutationCount.decrementAndGet();
+
+        synchronized (mLock) {
+            switch (args.table) {
+                case TABLE_GLOBAL: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return deleteGlobalSettingLocked(args.name, userId) ? 1 : 0;
+                }
+
+                case TABLE_SECURE: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return deleteSecureSettingLocked(args.name, userId) ? 1 : 0;
+                }
+
+                case TABLE_SYSTEM: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return deleteSystemSettingLocked(args.name, userId) ? 1 : 0;
+                }
+
+                default: {
+                    throw new IllegalArgumentException("Bad Uri path:" + uri);
+                }
+            }
         }
-        if (count > 0) {
-            invalidateCache(callingUser, args.table);  // before we notify
-            sendNotify(url, callingUser);
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "update() for user: " + UserHandle.getCallingUserId());
         }
-        startAsyncCachePopulation(callingUser);
-        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
-        return count;
+
+        Arguments args = new Arguments(uri, where, whereArgs, false);
+
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+            return 0;
+        }
+
+        String value = values.getAsString(Settings.Secure.VALUE);
+        if (TextUtils.isEmpty(value)) {
+            return 0;
+        }
+
+        synchronized (mLock) {
+            switch (args.table) {
+                case TABLE_GLOBAL: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return updateGlobalSettingLocked(args.name, value, userId) ? 1 : 0;
+                }
+
+                case TABLE_SECURE: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return updateSecureSettingLocked(args.name, value, userId) ? 1 : 0;
+                }
+
+                case TABLE_SYSTEM: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return updateSystemSettingLocked(args.name, value, userId) ? 1 : 0;
+                }
+
+                default: {
+                    throw new IllegalArgumentException("Invalid Uri path:" + uri);
+                }
+            }
+        }
     }
 
     @Override
@@ -1229,102 +479,1360 @@
                 + "ringtone playback is available through android.media.Ringtone");
     }
 
-    /**
-     * In-memory LRU Cache of system and secure settings, along with
-     * associated helper functions to keep cache coherent with the
-     * database.
+    private void registerBroadcastReceivers() {
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_STOPPED);
+
+        getContext().registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                        UserHandle.USER_OWNER);
+
+                switch (intent.getAction()) {
+                    case Intent.ACTION_USER_REMOVED: {
+                        mSettingsRegistry.removeUserStateLocked(userId, true);
+                    } break;
+
+                    case Intent.ACTION_USER_STOPPED: {
+                        mSettingsRegistry.removeUserStateLocked(userId, false);
+                    } break;
+                }
+            }
+        }, userFilter);
+
+        PackageMonitor monitor = new PackageMonitor() {
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                synchronized (mLock) {
+                    mSettingsRegistry.onPackageRemovedLocked(packageName,
+                            UserHandle.getUserId(uid));
+                }
+            }
+        };
+
+        // package changes
+        monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
+                UserHandle.ALL, true);
+    }
+
+    private Cursor getAllGlobalSettingsLocked(String[] projection) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getAllGlobalSettingsLocked()");
+        }
+
+        // Get the settings.
+        SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+                SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+
+        List<String> names = settingsState.getSettingNamesLocked();
+
+        final int nameCount = names.size();
+
+        String[] normalizedProjection = normalizeProjection(projection);
+        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+        // Anyone can get the global settings, so no security checks.
+        for (int i = 0; i < nameCount; i++) {
+            String name = names.get(i);
+            Setting setting = settingsState.getSettingLocked(name);
+            appendSettingToCursor(result, setting);
+        }
+
+        return result;
+    }
+
+    private Setting getGlobalSettingLocked(String name) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
+        }
+
+        // Get the value.
+        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                UserHandle.USER_OWNER, name);
+    }
+
+    private boolean updateGlobalSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "updateGlobalSettingLocked(" + name + ", " + value + ")");
+        }
+        return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+    }
+
+    private boolean insertGlobalSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertGlobalSettingLocked(" + name + ", " + value + ")");
+        }
+        return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteGlobalSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
+        }
+        return mutateGlobalSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+    }
+
+    private boolean mutateGlobalSettingLocked(String name, String value, int requestingUserId,
+            int operation) {
+        // Make sure the caller can change the settings - treated as secure.
+        enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // Verify whether this operation is allowed for the calling package.
+        if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+            return false;
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // If this is a setting that is currently restricted for this user, done.
+        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+            return false;
+        }
+
+        // Perform the mutation.
+        switch (operation) {
+            case MUTATION_OPERATION_INSERT: {
+                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                        UserHandle.USER_OWNER, name, value, getCallingPackage());
+            }
+
+            case MUTATION_OPERATION_DELETE: {
+                return mSettingsRegistry.deleteSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                        UserHandle.USER_OWNER, name);
+            }
+
+            case MUTATION_OPERATION_UPDATE: {
+                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                        UserHandle.USER_OWNER, name, value, getCallingPackage());
+            }
+        }
+
+        return false;
+    }
+
+    private Cursor getAllSecureSettingsLocked(int userId, String[] projection) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+        List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+                SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
+
+        final int nameCount = names.size();
+
+        String[] normalizedProjection = normalizeProjection(projection);
+        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+        for (int i = 0; i < nameCount; i++) {
+            String name = names.get(i);
+
+            // Determine the owning user as some profile settings are cloned from the parent.
+            final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+            // Special case for location (sigh).
+            if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+                return null;
+            }
+
+            Setting setting = mSettingsRegistry.getSettingLocked(
+                    SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
+            appendSettingToCursor(result, setting);
+        }
+
+        return result;
+    }
+
+    private Setting getSecureSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+        // Special case for location (sigh).
+        if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+            return null;
+        }
+
+        // Get the value.
+        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                owningUserId, name);
+    }
+
+    private boolean insertSecureSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertSecureSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteSecureSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "deleteSecureSettingLocked(" + name + ", " + requestingUserId + ")");
+        }
+
+        return mutateSecureSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+    }
+
+    private boolean updateSecureSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "updateSecureSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+    }
+
+    private boolean mutateSecureSettingLocked(String name, String value, int requestingUserId,
+            int operation) {
+        // Make sure the caller can change the settings.
+        enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // Verify whether this operation is allowed for the calling package.
+        if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+            return false;
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // If this is a setting that is currently restricted for this user, done.
+        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+            return false;
+        }
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+        // Only the owning user can change the setting.
+        if (owningUserId != callingUserId) {
+            return false;
+        }
+
+        // Special cases for location providers (sigh).
+        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+            return updateLocationProvidersAllowed(value, owningUserId);
+        }
+
+        // Mutate the value.
+        switch(operation) {
+            case MUTATION_OPERATION_INSERT: {
+                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                        owningUserId, name, value, getCallingPackage());
+            }
+
+            case MUTATION_OPERATION_DELETE: {
+                return mSettingsRegistry.deleteSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SECURE,
+                        owningUserId, name);
+            }
+
+            case MUTATION_OPERATION_UPDATE: {
+                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                        owningUserId, name, value, getCallingPackage());
+            }
+        }
+
+        return false;
+    }
+
+    private Cursor getAllSystemSettingsLocked(int userId, String[] projection) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getAllSecureSystemLocked(" + userId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+        List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+                SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
+
+        final int nameCount = names.size();
+
+        String[] normalizedProjection = normalizeProjection(projection);
+        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+        for (int i = 0; i < nameCount; i++) {
+            String name = names.get(i);
+
+            // Determine the owning user as some profile settings are cloned from the parent.
+            final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+            Setting setting = mSettingsRegistry.getSettingLocked(
+                    SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
+            appendSettingToCursor(result, setting);
+        }
+
+        return result;
+    }
+
+    private Setting getSystemSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+        // Get the value.
+        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                owningUserId, name);
+    }
+
+    private boolean insertSystemSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertSystemSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteSystemSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "deleteSystemSettingLocked(" + name + ", " + requestingUserId + ")");
+        }
+
+        return mutateSystemSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+    }
+
+    private boolean updateSystemSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "updateSystemSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+    }
+
+    private boolean mutateSystemSettingLocked(String name, String value, int runAsUserId,
+            int operation) {
+        // Make sure the caller can change the settings.
+        enforceWritePermission(Manifest.permission.WRITE_SETTINGS);
+
+        // Verify whether this operation is allowed for the calling package.
+        if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+            return false;
+        }
+
+        // Enforce what the calling package can mutate in the system settings.
+        enforceRestrictedSystemSettingsMutationForCallingPackageLocked(operation, name);
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+        // Only the owning user id can change the setting.
+        if (owningUserId != callingUserId) {
+            return false;
+        }
+
+        // Mutate the value.
+        switch (operation) {
+            case MUTATION_OPERATION_INSERT: {
+                validateSystemSettingValue(name, value);
+                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                        owningUserId, name, value, getCallingPackage());
+            }
+
+            case MUTATION_OPERATION_DELETE: {
+                return mSettingsRegistry.deleteSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                        owningUserId, name);
+            }
+
+            case MUTATION_OPERATION_UPDATE: {
+                validateSystemSettingValue(name, value);
+                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                        owningUserId, name, value, getCallingPackage());
+            }
+        }
+
+        return false;
+    }
+
+    private void validateSystemSettingValue(String name, String value) {
+        Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
+        if (validator != null && !validator.validate(value)) {
+            throw new IllegalArgumentException("Invalid value: " + value
+                    + " for setting: " + name);
+        }
+    }
+
+    private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId,
+            int owningUserId) {
+        // Optimization - location providers are restricted only for managed profiles.
+        if (callingUserId == owningUserId) {
+            return false;
+        }
+        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)
+                && mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+                new UserHandle(callingUserId))) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId) {
+        String restriction = sSettingToUserRestrictionMap.get(setting);
+        if (restriction == null) {
+            return false;
+        }
+        return mUserManager.hasUserRestriction(restriction, new UserHandle(userId));
+    }
+
+    private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
+        return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting);
+    }
+
+    private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
+        return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
+    }
+
+    private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) {
+        final int parentId = getGroupParentLocked(userId);
+        if (parentId != userId && keys.contains(name)) {
+            return parentId;
+        }
+        return userId;
+    }
+
+    private void enforceRestrictedSystemSettingsMutationForCallingPackageLocked(int operation,
+            String name) {
+        // System/root/shell can mutate whatever secure settings they want.
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid == android.os.Process.SYSTEM_UID
+                || callingUid == Process.SHELL_UID
+                || callingUid == Process.ROOT_UID) {
+            return;
+        }
+
+        switch (operation) {
+            case MUTATION_OPERATION_INSERT:
+                // Insert updates.
+            case MUTATION_OPERATION_UPDATE: {
+                if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
+                    return;
+                }
+
+                // The calling package is already verified.
+                PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+
+                // Privileged apps can do whatever they want.
+                if ((packageInfo.applicationInfo.privateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+                    return;
+                }
+
+                warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+                        packageInfo.applicationInfo.targetSdkVersion, name);
+            } break;
+
+            case MUTATION_OPERATION_DELETE: {
+                if (Settings.System.PUBLIC_SETTINGS.contains(name)
+                        || Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                    throw new IllegalArgumentException("You cannot delete system defined"
+                            + " secure settings.");
+                }
+
+                // The calling package is already verified.
+                PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+
+                // Privileged apps can do whatever they want.
+                if ((packageInfo.applicationInfo.privateFlags &
+                        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+                    return;
+                }
+
+                warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+                        packageInfo.applicationInfo.targetSdkVersion, name);
+            } break;
+        }
+    }
+
+    private PackageInfo getCallingPackageInfoOrThrow() {
+        try {
+            return mPackageManager.getPackageInfo(getCallingPackage(), 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Calling package doesn't exist");
+        }
+    }
+
+    private int getGroupParentLocked(int userId) {
+        // Most frequent use case.
+        if (userId == UserHandle.USER_OWNER) {
+            return userId;
+        }
+        // We are in the same process with the user manager and the returned
+        // user info is a cached instance, so just look up instead of cache.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            UserInfo userInfo = mUserManager.getProfileParent(userId);
+            return (userInfo != null) ? userInfo.id : userId;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private boolean isAppOpWriteSettingsAllowedForCallingPackage() {
+        final int callingUid = Binder.getCallingUid();
+
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), getCallingPackage());
+
+        return mAppOpsManager.noteOp(AppOpsManager.OP_WRITE_SETTINGS, callingUid,
+                getCallingPackage()) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    private void enforceWritePermission(String permission) {
+        if (getContext().checkCallingOrSelfPermission(permission)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Permission denial: writing to settings requires:"
+                    + permission);
+        }
+    }
+
+    /*
+     * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
+     * This setting contains a list of the currently enabled location providers.
+     * But helper functions in android.providers.Settings can enable or disable
+     * a single provider by using a "+" or "-" prefix before the provider name.
+     *
+     * @returns whether the enabled location providers changed.
      */
-    private static final class SettingsCache extends LruCache<String, Bundle> {
-
-        private final String mCacheName;
-        private boolean mCacheFullyMatchesDisk = false;  // has the whole database slurped.
-
-        public SettingsCache(String name) {
-            super(MAX_CACHE_ENTRIES);
-            mCacheName = name;
+    private boolean updateLocationProvidersAllowed(String value, int owningUserId) {
+        if (TextUtils.isEmpty(value)) {
+            return false;
         }
 
-        /**
-         * Is the whole database table slurped into this cache?
-         */
-        public boolean fullyMatchesDisk() {
-            synchronized (this) {
-                return mCacheFullyMatchesDisk;
+        final char prefix = value.charAt(0);
+        if (prefix != '+' && prefix != '-') {
+            return false;
+        }
+
+        // skip prefix
+        value = value.substring(1);
+
+        Setting settingValue = getSecureSettingLocked(
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
+
+        String oldProviders = (settingValue != null) ? settingValue.getValue() : "";
+
+        int index = oldProviders.indexOf(value);
+        int end = index + value.length();
+
+        // check for commas to avoid matching on partial string
+        if (index > 0 && oldProviders.charAt(index - 1) != ',') {
+            index = -1;
+        }
+
+        // check for commas to avoid matching on partial string
+        if (end < oldProviders.length() && oldProviders.charAt(end) != ',') {
+            index = -1;
+        }
+
+        String newProviders;
+
+        if (prefix == '+' && index < 0) {
+            // append the provider to the list if not present
+            if (oldProviders.length() == 0) {
+                newProviders = value;
+            } else {
+                newProviders = oldProviders + ',' + value;
+            }
+        } else if (prefix == '-' && index >= 0) {
+            // remove the provider from the list if present
+            // remove leading or trailing comma
+            if (index > 0) {
+                index--;
+            } else if (end < oldProviders.length()) {
+                end++;
+            }
+
+            newProviders = oldProviders.substring(0, index);
+            if (end < oldProviders.length()) {
+                newProviders += oldProviders.substring(end);
+            }
+        } else {
+            // nothing changed, so no need to update the database
+            return false;
+        }
+
+        updateSecureSettingLocked(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                newProviders, owningUserId);
+
+        return true;
+    }
+
+    private void sendNotify(Uri uri, int userId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            getContext().getContentResolver().notifyChange(uri, null, true, userId);
+            if (DEBUG) {
+                Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+            int targetSdkVersion, String name) {
+        // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash.
+        if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+            if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                Slog.w(LOG_TAG, "You shouldn't not change private system settings."
+                        + " This will soon become an error.");
+            } else {
+                Slog.w(LOG_TAG, "You shouldn't keep your settings in the secure settings."
+                        + " This will soon become an error.");
+            }
+        } else {
+            if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                throw new IllegalArgumentException("You cannot change private secure settings.");
+            } else {
+                throw new IllegalArgumentException("You cannot keep your settings in"
+                        + " the secure settings.");
+            }
+        }
+    }
+
+    private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) {
+        if (requestingUserId == UserHandle.getCallingUserId()) {
+            return requestingUserId;
+        }
+        return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), requestingUserId, false, true,
+                "get/set setting for user", null);
+    }
+
+    private static Bundle packageValueForCallResult(Setting setting) {
+        if (setting == null) {
+            return NULL_SETTING;
+        }
+        return Bundle.forPair(Settings.NameValueTable.VALUE, setting.getValue());
+    }
+
+    private static int getRequestingUserId(Bundle args) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId)
+                : callingUserId;
+    }
+
+    private static String getSettingValue(Bundle args) {
+        return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null;
+    }
+
+    private static String getValidTableOrThrow(Uri uri) {
+        if (uri.getPathSegments().size() > 0) {
+            String table = uri.getPathSegments().get(0);
+            if (DatabaseHelper.isValidTable(table)) {
+                return table;
+            }
+            throw new IllegalArgumentException("Bad root path: " + table);
+        }
+        throw new IllegalArgumentException("Invalid URI:" + uri);
+    }
+
+    private static MatrixCursor packageSettingForQuery(Setting setting, String[] projection) {
+        if (setting == null) {
+            return new MatrixCursor(projection, 0);
+        }
+        MatrixCursor cursor = new MatrixCursor(projection, 1);
+        appendSettingToCursor(cursor, setting);
+        return cursor;
+    }
+
+    private static String[] normalizeProjection(String[] projection) {
+        if (projection == null) {
+            return ALL_COLUMNS;
+        }
+
+        final int columnCount = projection.length;
+        for (int i = 0; i < columnCount; i++) {
+            String column = projection[i];
+            if (!ArrayUtils.contains(ALL_COLUMNS, column)) {
+                throw new IllegalArgumentException("Invalid column: " + column);
             }
         }
 
-        public void setFullyMatchesDisk(boolean value) {
-            synchronized (this) {
-                mCacheFullyMatchesDisk = value;
+        return projection;
+    }
+
+    private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) {
+        final int columnCount = cursor.getColumnCount();
+
+        String[] values =  new String[columnCount];
+
+        for (int i = 0; i < columnCount; i++) {
+            String column = cursor.getColumnName(i);
+
+            switch (column) {
+                case Settings.NameValueTable._ID: {
+                    values[i] = setting.getId();
+                } break;
+
+                case Settings.NameValueTable.NAME: {
+                    values[i] = setting.getName();
+                } break;
+
+                case Settings.NameValueTable.VALUE: {
+                    values[i] = setting.getValue();
+                } break;
             }
         }
 
-        @Override
-        protected void entryRemoved(boolean evicted, String key, Bundle oldValue, Bundle newValue) {
-            if (evicted) {
-                mCacheFullyMatchesDisk = false;
-            }
-        }
+        cursor.addRow(values);
+    }
 
-        /**
-         * Atomic cache population, conditional on size of value and if
-         * we lost a race.
-         *
-         * @returns a Bundle to send back to the client from call(), even
-         *     if we lost the race.
-         */
-        public Bundle putIfAbsent(String key, String value) {
-            Bundle bundle = (value == null) ? NULL_SETTING : Bundle.forPair("value", value);
-            if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
-                synchronized (this) {
-                    if (get(key) == null) {
-                        put(key, bundle);
+    private static final class Arguments {
+        private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
+                Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
+
+        private static final Pattern WHERE_PATTERN_WITH_PARAM_IN_BRACKETS =
+                Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*\\?[\\s]*\\)[\\s]*");
+
+        private static final Pattern WHERE_PATTERN_NO_PARAM_IN_BRACKETS =
+                Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*\\)[\\s]*");
+
+        private static final Pattern WHERE_PATTERN_NO_PARAM_NO_BRACKETS =
+                Pattern.compile("[\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*");
+
+        public final String table;
+        public final String name;
+
+        public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) {
+            final int segmentSize = uri.getPathSegments().size();
+            switch (segmentSize) {
+                case 1: {
+                    if (where != null
+                            && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches()
+                                || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
+                            && whereArgs.length == 1) {
+                        name = whereArgs[0];
+                        table = computeTableForSetting(uri, name);
+                    } else if (where != null
+                            && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
+                                || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
+                        final int startIndex = Math.max(where.indexOf("'"),
+                                where.indexOf("\"")) + 1;
+                        final int endIndex = Math.max(where.lastIndexOf("'"),
+                                where.lastIndexOf("\""));
+                        name = where.substring(startIndex, endIndex);
+                        table = computeTableForSetting(uri, name);
+                    } else if (supportAll && where == null && whereArgs == null) {
+                        name = null;
+                        table = computeTableForSetting(uri, null);
+                    } else if (uri.getPathSegments().size() == 2
+                            && where == null && whereArgs == null) {
+                        name = uri.getPathSegments().get(1);
+                        table = computeTableForSetting(uri, name);
+                    } else {
+                        EventLogTags.writeUnsupportedSettingsQuery(
+                                uri.toSafeString(), where, Arrays.toString(whereArgs));
+                        throw new IllegalArgumentException("Only null where and args"
+                                + " or name=? where and a single arg or name='SOME_SETTING' "
+                                + "are supported uri: " + uri + " where: " + where + " args: "
+                                + Arrays.toString(whereArgs));
                     }
+                } break;
+
+                default: {
+                    throw new IllegalArgumentException("Invalid URI: " + uri);
                 }
             }
-            return bundle;
         }
 
-        /**
-         * Populates a key in a given (possibly-null) cache.
-         */
-        public static void populate(SettingsCache cache, ContentValues contentValues) {
-            if (cache == null) {
-                return;
+        public static String computeTableForSetting(Uri uri, String name) {
+            String table = getValidTableOrThrow(uri);
+
+            if (name != null) {
+                if (sSystemMovedToSecureSettings.contains(name)) {
+                    table = TABLE_SECURE;
+                }
+
+                if (sSystemMovedToGlobalSettings.contains(name)) {
+                    table = TABLE_GLOBAL;
+                }
+
+                if (sSecureMovedToGlobalSettings.contains(name)) {
+                    table = TABLE_GLOBAL;
+                }
+
+                if (sGlobalMovedToSecureSettings.contains(name)) {
+                    table = TABLE_SECURE;
+                }
             }
-            String name = contentValues.getAsString(Settings.NameValueTable.NAME);
-            if (name == null) {
-                Log.w(TAG, "null name populating settings cache.");
-                return;
-            }
-            String value = contentValues.getAsString(Settings.NameValueTable.VALUE);
-            cache.populate(name, value);
+
+            return table;
+        }
+    }
+
+    final class SettingsRegistry {
+        private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
+
+        private static final int SETTINGS_TYPE_GLOBAL = 0;
+        private static final int SETTINGS_TYPE_SYSTEM = 1;
+        private static final int SETTINGS_TYPE_SECURE = 2;
+
+        private static final int SETTINGS_TYPE_MASK = 0xF0000000;
+        private static final int SETTINGS_TYPE_SHIFT = 28;
+
+        private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
+        private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
+        private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
+
+        private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
+
+        private final BackupManager mBackupManager;
+
+        public SettingsRegistry() {
+            mBackupManager = new BackupManager(getContext());
+            migrateAllLegacySettingsIfNeeded();
         }
 
-        public void populate(String name, String value) {
-            synchronized (this) {
-                if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
-                    put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
+        public List<String> getSettingsNamesLocked(int type, int userId) {
+            final int key = makeKey(type, userId);
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            return settingsState.getSettingNamesLocked();
+        }
+
+        public SettingsState getSettingsLocked(int type, int userId) {
+            final int key = makeKey(type, userId);
+            return peekSettingsStateLocked(key);
+        }
+
+        public void ensureSettingsForUserLocked(int userId) {
+            // Migrate the setting for this user if needed.
+            migrateLegacySettingsForUserIfNeededLocked(userId);
+
+            // Ensure global settings loaded if owner.
+            if (userId == UserHandle.USER_OWNER) {
+                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                ensureSettingsStateLocked(globalKey);
+            }
+
+            // Ensure secure settings loaded.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            ensureSettingsStateLocked(secureKey);
+
+            // Make sure the secure settings have an Android id set.
+            SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
+            ensureSecureSettingAndroidIdSetLocked(secureSettings);
+
+            // Ensure system settings loaded.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            ensureSettingsStateLocked(systemKey);
+
+            // Upgrade the settings to the latest version.
+            UpgradeController upgrader = new UpgradeController(userId);
+            upgrader.upgradeIfNeededLocked();
+        }
+
+        private void ensureSettingsStateLocked(int key) {
+            if (mSettingsStates.get(key) == null) {
+                final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
+                SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
+                        maxBytesPerPackage);
+                mSettingsStates.put(key, settingsState);
+            }
+        }
+
+        public void removeUserStateLocked(int userId, boolean permanently) {
+            // We always keep the global settings in memory.
+
+            // Nuke system settings.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
+            if (systemSettingsState != null) {
+                if (permanently) {
+                    mSettingsStates.remove(systemKey);
+                    systemSettingsState.destroyLocked(null);
                 } else {
-                    put(name, TOO_LARGE_TO_CACHE_MARKER);
+                    systemSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(systemKey);
+                        }
+                    });
+                }
+            }
+
+            // Nuke secure settings.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
+            if (secureSettingsState != null) {
+                if (permanently) {
+                    mSettingsStates.remove(secureKey);
+                    secureSettingsState.destroyLocked(null);
+                } else {
+                    secureSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(secureKey);
+                        }
+                    });
                 }
             }
         }
 
-        /**
-         * For suppressing duplicate/redundant settings inserts early,
-         * checking our cache first (but without faulting it in),
-         * before going to sqlite with the mutation.
-         */
-        public static boolean isRedundantSetValue(SettingsCache cache, String name, String value) {
-            if (cache == null) return false;
-            synchronized (cache) {
-                Bundle bundle = cache.get(name);
-                if (bundle == null) return false;
-                String oldValue = bundle.getPairValue();
-                if (oldValue == null && value == null) return true;
-                if ((oldValue == null) != (value == null)) return false;
-                return oldValue.equals(value);
+        public boolean insertSettingLocked(int type, int userId, String name, String value,
+                String packageName) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            final boolean success = settingsState.insertSettingLocked(name, value, packageName);
+
+            if (success) {
+                notifyForSettingsChange(key, name);
+            }
+            return success;
+        }
+
+        public boolean deleteSettingLocked(int type, int userId, String name) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            final boolean success = settingsState.deleteSettingLocked(name);
+
+            if (success) {
+                notifyForSettingsChange(key, name);
+            }
+            return success;
+        }
+
+        public Setting getSettingLocked(int type, int userId, String name) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            return settingsState.getSettingLocked(name);
+        }
+
+        public boolean updateSettingLocked(int type, int userId, String name, String value,
+                String packageName) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            final boolean success = settingsState.updateSettingLocked(name, value, packageName);
+
+            if (success) {
+                notifyForSettingsChange(key, name);
+            }
+
+            return success;
+        }
+
+        public void onPackageRemovedLocked(String packageName, int userId) {
+            final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+            SettingsState globalSettings = mSettingsStates.get(globalKey);
+            globalSettings.onPackageRemovedLocked(packageName);
+
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            SettingsState secureSettings = mSettingsStates.get(secureKey);
+            secureSettings.onPackageRemovedLocked(packageName);
+
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            SettingsState systemSettings = mSettingsStates.get(systemKey);
+            systemSettings.onPackageRemovedLocked(packageName);
+        }
+
+        private SettingsState peekSettingsStateLocked(int key) {
+            SettingsState settingsState = mSettingsStates.get(key);
+            if (settingsState != null) {
+                return settingsState;
+            }
+
+            ensureSettingsForUserLocked(getUserIdFromKey(key));
+            return mSettingsStates.get(key);
+        }
+
+        private void migrateAllLegacySettingsIfNeeded() {
+            synchronized (mLock) {
+                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                File globalFile = getSettingsFile(key);
+                if (globalFile.exists()) {
+                    return;
+                }
+
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    List<UserInfo> users = mUserManager.getUsers(true);
+
+                    final int userCount = users.size();
+                    for (int i = 0; i < userCount; i++) {
+                        final int userId = users.get(i).id;
+
+                        DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+                        SQLiteDatabase database = dbHelper.getWritableDatabase();
+                        migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+
+                        // Upgrade to the latest version.
+                        UpgradeController upgrader = new UpgradeController(userId);
+                        upgrader.upgradeIfNeededLocked();
+
+                        // Drop from memory if not a running user.
+                        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
+                            removeUserStateLocked(userId, false);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
+            // Every user has secure settings and if no file we need to migrate.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            File secureFile = getSettingsFile(secureKey);
+            if (secureFile.exists()) {
+                return;
+            }
+
+            DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+            SQLiteDatabase database = dbHelper.getWritableDatabase();
+
+            migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+        }
+
+        private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
+                SQLiteDatabase database, int userId) {
+            // Move over the global settings if owner.
+            if (userId == UserHandle.USER_OWNER) {
+                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
+                ensureSettingsStateLocked(globalKey);
+                SettingsState globalSettings = mSettingsStates.get(globalKey);
+                migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
+                globalSettings.persistSyncLocked();
+            }
+
+            // Move over the secure settings.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            ensureSettingsStateLocked(secureKey);
+            SettingsState secureSettings = mSettingsStates.get(secureKey);
+            migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
+            ensureSecureSettingAndroidIdSetLocked(secureSettings);
+            secureSettings.persistSyncLocked();
+
+            // Move over the system settings.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            ensureSettingsStateLocked(systemKey);
+            SettingsState systemSettings = mSettingsStates.get(systemKey);
+            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
+            systemSettings.persistSyncLocked();
+
+            // Drop the database as now all is moved and persisted.
+            if (DROP_DATABASE_ON_MIGRATION) {
+                dbHelper.dropDatabase();
+            } else {
+                dbHelper.backupDatabase();
+            }
+        }
+
+        private void migrateLegacySettingsLocked(SettingsState settingsState,
+                SQLiteDatabase database, String table) {
+            SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
+            queryBuilder.setTables(table);
+
+            Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
+                    null, null, null, null, null);
+
+            if (cursor == null) {
+                return;
+            }
+
+            try {
+                if (!cursor.moveToFirst()) {
+                    return;
+                }
+
+                final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+                final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
+                settingsState.setVersionLocked(database.getVersion());
+
+                while (!cursor.isAfterLast()) {
+                    String name = cursor.getString(nameColumnIdx);
+                    String value = cursor.getString(valueColumnIdx);
+                    settingsState.insertSettingLocked(name, value,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                    cursor.moveToNext();
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+
+        private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
+            Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
+
+            if (value != null) {
+                return;
+            }
+
+            final int userId = getUserIdFromKey(secureSettings.mKey);
+
+            final UserInfo user;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                user = mUserManager.getUserInfo(userId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            if (user == null) {
+                // Can happen due to races when deleting users - treat as benign.
+                return;
+            }
+
+            String androidId = Long.toHexString(new SecureRandom().nextLong());
+            secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
+                    SettingsState.SYSTEM_PACKAGE_NAME);
+
+            Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
+                    + "] for user " + userId);
+
+            // Write a drop box entry if it's a restricted profile
+            if (user.isRestricted()) {
+                DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
+                        Context.DROPBOX_SERVICE);
+                if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
+                    dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
+                            + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
+                }
+            }
+        }
+
+        private void notifyForSettingsChange(int key, String name) {
+            // Update the system property *first*, so if someone is listening for
+            // a notification and then using the contract class to get their data,
+            // the system property will be updated and they'll get the new data.
+
+            boolean backedUpDataChanged = false;
+            String property = null;
+            if (isGlobalSettingsKey(key)) {
+                property = Settings.Global.SYS_PROP_SETTING_VERSION;
+                backedUpDataChanged = true;
+            } else if (isSecureSettingsKey(key)) {
+                property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+                backedUpDataChanged = true;
+            } else if (isSystemSettingsKey(key)) {
+                property = Settings.System.SYS_PROP_SETTING_VERSION;
+                backedUpDataChanged = true;
+            }
+
+            if (property != null) {
+                final long version = SystemProperties.getLong(property, 0) + 1;
+                SystemProperties.set(property, Long.toString(version));
+                if (DEBUG) {
+                    Slog.v(LOG_TAG, "System property " + property + "=" + version);
+                }
+            }
+
+            // Inform the backup manager about a data change
+            if (backedUpDataChanged) {
+                mBackupManager.dataChanged();
+            }
+
+            // Now send the notification through the content framework.
+
+            final int userId = getUserIdFromKey(key);
+            Uri uri = getNotificationUriFor(key, name);
+
+            sendNotify(uri, userId);
+        }
+
+        private int makeKey(int type, int userId) {
+            return (type << SETTINGS_TYPE_SHIFT) | userId;
+        }
+
+        private int getTypeFromKey(int key) {
+            return key >> SETTINGS_TYPE_SHIFT;
+        }
+
+        private int getUserIdFromKey(int key) {
+            return key & ~SETTINGS_TYPE_MASK;
+        }
+
+        private boolean isGlobalSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
+        }
+
+        private boolean isSystemSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
+        }
+
+        private boolean isSecureSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
+        }
+
+        private File getSettingsFile(int key) {
+            if (isGlobalSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_GLOBAL);
+            } else if (isSystemSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SYSTEM);
+            } else if (isSecureSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SECURE);
+            } else {
+                throw new IllegalArgumentException("Invalid settings key:" + key);
+            }
+        }
+
+        private Uri getNotificationUriFor(int key, String name) {
+            if (isGlobalSettingsKey(key)) {
+                return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
+                        : Settings.Global.CONTENT_URI;
+            } else if (isSecureSettingsKey(key)) {
+                return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
+                        : Settings.Secure.CONTENT_URI;
+            } else if (isSystemSettingsKey(key)) {
+                return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
+                        : Settings.System.CONTENT_URI;
+            } else {
+                throw new IllegalArgumentException("Invalid settings key:" + key);
+            }
+        }
+
+        private int getMaxBytesPerPackageForType(int type) {
+            switch (type) {
+                case SETTINGS_TYPE_GLOBAL:
+                case SETTINGS_TYPE_SECURE: {
+                    return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
+                }
+
+                default: {
+                    return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
+                }
+            }
+        }
+
+        private final class UpgradeController {
+            private static final int SETTINGS_VERSION = 118;
+
+            private final int mUserId;
+
+            public UpgradeController(int userId) {
+                mUserId = userId;
+            }
+
+            public void upgradeIfNeededLocked() {
+                // The version of all settings for a user is the same (all users have secure).
+                SettingsState secureSettings = getSettingsLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
+
+                // Try an update from the current state.
+                final int oldVersion = secureSettings.getVersionLocked();
+                final int newVersion = SETTINGS_VERSION;
+
+                // If up do data - done.
+                if (oldVersion == newVersion) {
+                    return;
+                }
+
+                // Try to upgrade.
+                final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
+
+                // If upgrade failed start from scratch and upgrade.
+                if (curVersion != newVersion) {
+                    // Drop state we have for this user.
+                    removeUserStateLocked(mUserId, true);
+
+                    // Recreate the database.
+                    DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
+                    SQLiteDatabase database = dbHelper.getWritableDatabase();
+                    dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
+
+                    // Migrate the settings for this user.
+                    migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
+
+                    // Now upgrade should work fine.
+                    onUpgradeLocked(mUserId, oldVersion, newVersion);
+                }
+
+                // Set the global settings version if owner.
+                if (mUserId == UserHandle.USER_OWNER) {
+                    SettingsState globalSettings = getSettingsLocked(
+                            SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
+                    globalSettings.setVersionLocked(newVersion);
+                }
+
+                // Set the secure settings version.
+                secureSettings.setVersionLocked(newVersion);
+
+                // Set the system settings version.
+                SettingsState systemSettings = getSettingsLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
+                systemSettings.setVersionLocked(newVersion);
+            }
+
+            private SettingsState getGlobalSettingsLocked() {
+                return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+            }
+
+            private SettingsState getSecureSettingsLocked(int userId) {
+                return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
+            }
+
+            private SettingsState getSystemSettingsLocked(int userId) {
+                return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
+            }
+
+            private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
+                if (DEBUG) {
+                    Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
+                            + oldVersion + " to version: " + newVersion);
+                }
+
+                // You must perform all necessary mutations to bring the settings
+                // for this user from the old to the new version. When you add a new
+                // upgrade step you *must* update SETTINGS_VERSION.
+
+                /**
+                 * This is an example of moving a setting from secure to global.
+                 *
+                 * int currentVersion = oldVersion;
+                 * if (currentVersion == 118) {
+                 *     // Remove from the secure settings.
+                 *     SettingsState secureSettings = getSecureSettingsLocked(userId);
+                 *     String name = "example_setting_to_move";
+                 *     String value = secureSettings.getSetting(name);
+                 *     secureSettings.deleteSetting(name);
+                 *
+                 *     // Add to the global settings.
+                 *     SettingsState globalSettings = getGlobalSettingsLocked();
+                 *     globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
+                 *
+                 *     // Update the current version.
+                 *     currentVersion = 119;
+                 * }
+                 *
+                 * // Return the current version.
+                 * return currentVersion;
+                 */
+
+                return SettingsState.VERSION_UNDEFINED;
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
new file mode 100644
index 0000000..e63d220
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -0,0 +1,574 @@
+/*
+ * 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.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import libcore.io.IoUtils;
+import libcore.util.Objects;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class contains the state for one type of settings. It is responsible
+ * for saving the state asynchronously to an XML file after a mutation and
+ * loading the from an XML file on construction.
+ * <p>
+ * This class uses the same lock as the settings provider to ensure that
+ * multiple changes made by the settings provider, e,g, upgrade, bulk insert,
+ * etc, are atomically persisted since the asynchronous persistence is using
+ * the same lock to grab the current state to write to disk.
+ * </p>
+ */
+final class SettingsState {
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_PERSISTENCE = false;
+
+    private static final String LOG_TAG = "SettingsState";
+
+    private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
+    private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;
+
+    public static final int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1;
+    public static final int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000;
+
+    public static final String SYSTEM_PACKAGE_NAME = "android";
+
+    public static final int VERSION_UNDEFINED = -1;
+
+    private static final String TAG_SETTINGS = "settings";
+    private static final String TAG_SETTING = "setting";
+    private static final String ATTR_PACKAGE = "package";
+
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_ID = "id";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_VALUE = "value";
+
+    private static final String NULL_VALUE = "null";
+
+    private final Object mLock;
+
+    private final Handler mHandler = new MyHandler();
+
+    @GuardedBy("mLock")
+    private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();
+
+    @GuardedBy("mLock")
+    private final ArrayMap<String, Integer> mPackageToMemoryUsage;
+
+    @GuardedBy("mLock")
+    private final int mMaxBytesPerAppPackage;
+
+    @GuardedBy("mLock")
+    private final File mStatePersistFile;
+
+    public final int mKey;
+
+    @GuardedBy("mLock")
+    private int mVersion = VERSION_UNDEFINED;
+
+    @GuardedBy("mLock")
+    private long mLastNotWrittenMutationTimeMillis;
+
+    @GuardedBy("mLock")
+    private boolean mDirty;
+
+    @GuardedBy("mLock")
+    private boolean mWriteScheduled;
+
+    public SettingsState(Object lock, File file, int key, int maxBytesPerAppPackage) {
+        // It is important that we use the same lock as the settings provider
+        // to ensure multiple mutations on this state are atomicaly persisted
+        // as the async persistence should be blocked while we make changes.
+        mLock = lock;
+        mStatePersistFile = file;
+        mKey = key;
+        if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) {
+            mMaxBytesPerAppPackage = maxBytesPerAppPackage;
+            mPackageToMemoryUsage = new ArrayMap<>();
+        } else {
+            mMaxBytesPerAppPackage = maxBytesPerAppPackage;
+            mPackageToMemoryUsage = null;
+        }
+        synchronized (mLock) {
+            readStateSyncLocked();
+        }
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public int getVersionLocked() {
+        return mVersion;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void setVersionLocked(int version) {
+        if (version == mVersion) {
+            return;
+        }
+        mVersion = version;
+
+        scheduleWriteIfNeededLocked();
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void onPackageRemovedLocked(String packageName) {
+        boolean removedSomething = false;
+
+        final int settingCount = mSettings.size();
+        for (int i = settingCount - 1; i >= 0; i--) {
+            String name = mSettings.keyAt(i);
+            // Settings defined by use are never dropped.
+            if (Settings.System.PUBLIC_SETTINGS.contains(name)
+                    || Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                continue;
+            }
+            Setting setting = mSettings.valueAt(i);
+            if (packageName.equals(setting.packageName)) {
+                mSettings.removeAt(i);
+                removedSomething = true;
+            }
+        }
+
+        if (removedSomething) {
+            scheduleWriteIfNeededLocked();
+        }
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public List<String> getSettingNamesLocked() {
+        ArrayList<String> names = new ArrayList<>();
+        final int settingsCount = mSettings.size();
+        for (int i = 0; i < settingsCount; i++) {
+            String name = mSettings.keyAt(i);
+            names.add(name);
+        }
+        return names;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public Setting getSettingLocked(String name) {
+        if (TextUtils.isEmpty(name)) {
+            return null;
+        }
+        return mSettings.get(name);
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public boolean updateSettingLocked(String name, String value, String packageName) {
+        if (!hasSettingLocked(name)) {
+            return false;
+        }
+
+        return insertSettingLocked(name, value, packageName);
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public boolean insertSettingLocked(String name, String value, String packageName) {
+        if (TextUtils.isEmpty(name)) {
+            return false;
+        }
+
+        Setting oldState = mSettings.get(name);
+        String oldValue = (oldState != null) ? oldState.value : null;
+
+        if (oldState != null) {
+            if (!oldState.update(value, packageName)) {
+                return false;
+            }
+        } else {
+            Setting state = new Setting(name, value, packageName);
+            mSettings.put(name, state);
+        }
+
+        updateMemoryUsagePerPackageLocked(packageName, oldValue, value);
+
+        scheduleWriteIfNeededLocked();
+
+        return true;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void persistSyncLocked() {
+        mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+        doWriteState();
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public boolean deleteSettingLocked(String name) {
+        if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
+            return false;
+        }
+
+        Setting oldState = mSettings.remove(name);
+
+        updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null);
+
+        scheduleWriteIfNeededLocked();
+
+        return true;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void destroyLocked(Runnable callback) {
+        mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+        if (callback != null) {
+            if (mDirty) {
+                // Do it without a delay.
+                mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS,
+                        callback).sendToTarget();
+                return;
+            }
+            callback.run();
+        }
+    }
+
+    private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
+            String newValue) {
+        if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
+            return;
+        }
+
+        if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
+            return;
+        }
+
+        final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
+        final int newValueSize = (newValue != null) ? newValue.length() : 0;
+        final int deltaSize = newValueSize - oldValueSize;
+
+        Integer currentSize = mPackageToMemoryUsage.get(packageName);
+        final int newSize = Math.max((currentSize != null)
+                ? currentSize + deltaSize : deltaSize, 0);
+
+        if (newSize > mMaxBytesPerAppPackage) {
+            throw new IllegalStateException("You are adding too many system settings. "
+                    + "You should stop using system settings for app specific data.");
+        }
+
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "Settings for package: " + packageName
+                    + " size: " + newSize + " bytes.");
+        }
+
+        mPackageToMemoryUsage.put(packageName, newSize);
+    }
+
+    private boolean hasSettingLocked(String name) {
+        return mSettings.indexOfKey(name) >= 0;
+    }
+
+    private void scheduleWriteIfNeededLocked() {
+        // If dirty then we have a write already scheduled.
+        if (!mDirty) {
+            mDirty = true;
+            writeStateAsyncLocked();
+        }
+    }
+
+    private void writeStateAsyncLocked() {
+        final long currentTimeMillis = SystemClock.uptimeMillis();
+
+        if (mWriteScheduled) {
+            mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+
+            // If enough time passed, write without holding off anymore.
+            final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+                    - mLastNotWrittenMutationTimeMillis;
+            if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_SETTINGS_DELAY_MILLIS) {
+                mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS).sendToTarget();
+                return;
+            }
+
+            // Hold off a bit more as settings are frequently changing.
+            final long maxDelayMillis = Math.max(mLastNotWrittenMutationTimeMillis
+                    + MAX_WRITE_SETTINGS_DELAY_MILLIS - currentTimeMillis, 0);
+            final long writeDelayMillis = Math.min(WRITE_SETTINGS_DELAY_MILLIS, maxDelayMillis);
+
+            Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);
+            mHandler.sendMessageDelayed(message, writeDelayMillis);
+        } else {
+            mLastNotWrittenMutationTimeMillis = currentTimeMillis;
+            Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);
+            mHandler.sendMessageDelayed(message, WRITE_SETTINGS_DELAY_MILLIS);
+            mWriteScheduled = true;
+        }
+    }
+
+    private void doWriteState() {
+        if (DEBUG_PERSISTENCE) {
+            Slog.i(LOG_TAG, "[PERSIST START]");
+        }
+
+        AtomicFile destination = new AtomicFile(mStatePersistFile);
+
+        final int version;
+        final ArrayMap<String, Setting> settings;
+
+        synchronized (mLock) {
+            version = mVersion;
+            settings = new ArrayMap<>(mSettings);
+            mDirty = false;
+            mWriteScheduled = false;
+        }
+
+        FileOutputStream out = null;
+        try {
+            out = destination.startWrite();
+
+            XmlSerializer serializer = Xml.newSerializer();
+            serializer.setOutput(out, "utf-8");
+            serializer.startDocument(null, true);
+            serializer.startTag(null, TAG_SETTINGS);
+            serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
+
+            final int settingCount = settings.size();
+            for (int i = 0; i < settingCount; i++) {
+                Setting setting = settings.valueAt(i);
+
+                serializer.startTag(null, TAG_SETTING);
+                serializer.attribute(null, ATTR_ID, setting.getId());
+                serializer.attribute(null, ATTR_NAME, setting.getName());
+                serializer.attribute(null, ATTR_VALUE, packValue(setting.getValue()));
+                serializer.attribute(null, ATTR_PACKAGE, packValue(setting.getPackageName()));
+                serializer.endTag(null, TAG_SETTING);
+
+                if (DEBUG_PERSISTENCE) {
+                    Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue());
+                }
+            }
+
+            serializer.endTag(null, TAG_SETTINGS);
+            serializer.endDocument();
+            destination.finishWrite(out);
+
+            if (DEBUG_PERSISTENCE) {
+                Slog.i(LOG_TAG, "[PERSIST END]");
+            }
+
+        } catch (IOException e) {
+            Slog.w(LOG_TAG, "Failed to write settings, restoring backup", e);
+            destination.failWrite(out);
+        } finally {
+            IoUtils.closeQuietly(out);
+        }
+    }
+
+    private void readStateSyncLocked() {
+        FileInputStream in;
+        if (!mStatePersistFile.exists()) {
+            return;
+        }
+        try {
+            in = new FileInputStream(mStatePersistFile);
+        } catch (FileNotFoundException fnfe) {
+            Slog.i(LOG_TAG, "No settings state");
+            return;
+        }
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(in, null);
+            parseStateLocked(parser);
+        } catch (XmlPullParserException | IOException ise) {
+            throw new IllegalStateException("Failed parsing settings file: "
+                    + mStatePersistFile , ise);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    private void parseStateLocked(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        parser.next();
+        skipEmptyTextTags(parser);
+        expect(parser, XmlPullParser.START_TAG, TAG_SETTINGS);
+
+        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+
+        parser.next();
+
+        while (parseSettingLocked(parser)) {
+            parser.next();
+        }
+
+        skipEmptyTextTags(parser);
+        expect(parser, XmlPullParser.END_TAG, TAG_SETTINGS);
+    }
+
+    private boolean parseSettingLocked(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        skipEmptyTextTags(parser);
+        if (!accept(parser, XmlPullParser.START_TAG, TAG_SETTING)) {
+            return false;
+        }
+
+        String id = parser.getAttributeValue(null, ATTR_ID);
+        String name = parser.getAttributeValue(null, ATTR_NAME);
+        String value = parser.getAttributeValue(null, ATTR_VALUE);
+        String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+        mSettings.put(name, new Setting(name, unpackValue(value),
+                unpackValue(packageName), id));
+
+        if (DEBUG_PERSISTENCE) {
+            Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value);
+        }
+
+        parser.next();
+
+        skipEmptyTextTags(parser);
+        expect(parser, XmlPullParser.END_TAG, TAG_SETTING);
+
+        return true;
+    }
+
+    private void expect(XmlPullParser parser, int type, String tag)
+            throws IOException, XmlPullParserException {
+        if (!accept(parser, type, tag)) {
+            throw new XmlPullParserException("Expected event: " + type
+                    + " and tag: " + tag + " but got event: " + parser.getEventType()
+                    + " and tag:" + parser.getName());
+        }
+    }
+
+    private void skipEmptyTextTags(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        while (accept(parser, XmlPullParser.TEXT, null)
+                && "\n".equals(parser.getText())) {
+            parser.next();
+        }
+    }
+
+    private boolean accept(XmlPullParser parser, int type, String tag)
+            throws IOException, XmlPullParserException {
+        if (parser.getEventType() != type) {
+            return false;
+        }
+        if (tag != null) {
+            if (!tag.equals(parser.getName())) {
+                return false;
+            }
+        } else if (parser.getName() != null) {
+            return false;
+        }
+        return true;
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_PERSIST_SETTINGS = 1;
+
+        public MyHandler() {
+            super(BackgroundThread.getHandler().getLooper());
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_PERSIST_SETTINGS: {
+                    Runnable callback = (Runnable) message.obj;
+                    doWriteState();
+                    if (callback != null) {
+                        callback.run();
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    private static String packValue(String value) {
+        if (value == null) {
+            return NULL_VALUE;
+        }
+        return value;
+    }
+
+    private static String unpackValue(String value) {
+        if (NULL_VALUE.equals(value)) {
+            return null;
+        }
+        return value;
+    }
+
+    public static final class Setting {
+        private static long sNextId;
+
+        private String name;
+        private String value;
+        private String packageName;
+        private String id;
+
+        public Setting(String name, String value, String packageName) {
+            init(name, value, packageName, String.valueOf(sNextId++));
+        }
+
+        public Setting(String name, String value, String packageName, String id) {
+            sNextId = Math.max(sNextId, Long.valueOf(id));
+            init(name, value, packageName, String.valueOf(sNextId));
+        }
+
+        private void init(String name, String value, String packageName, String id) {
+            this.name = name;
+            this.value = value;
+            this.packageName = packageName;
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public String getPackageName() {
+            return packageName;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public boolean update(String value, String packageName) {
+            if (Objects.equal(value, this.value)) {
+                return false;
+            }
+            this.value = value;
+            this.packageName = packageName;
+            this.id = String.valueOf(sNextId++);
+            return true;
+        }
+    }
+}
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
new file mode 100644
index 0000000..01c6ccf
--- /dev/null
+++ b/packages/SettingsProvider/test/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SettingsProviderTest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
new file mode 100644
index 0000000..7a86b5f
--- /dev/null
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.providers.setting.test">
+
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.providers.setting.test"
+        android:label="Settings Provider Tests" />
+</manifest>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
new file mode 100644
index 0000000..f713c33
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for the SettingContentProvider tests.
+ */
+abstract class BaseSettingsProviderTest extends AndroidTestCase {
+    protected static final int SETTING_TYPE_GLOBAL = 1;
+    protected static final int SETTING_TYPE_SECURE = 2;
+    protected static final int SETTING_TYPE_SYSTEM = 3;
+
+    protected static final String FAKE_SETTING_NAME = "fake_setting_name";
+    protected static final String FAKE_SETTING_NAME_1 = "fake_setting_name1";
+    protected static final String FAKE_SETTING_VALUE = "fake_setting_value";
+    protected static final String FAKE_SETTING_VALUE_1 = "fake_setting_value_1";
+
+    private static final String[] NAME_VALUE_COLUMNS = new String[] {
+            Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
+    };
+
+    protected int mSecondaryUserId = UserHandle.USER_OWNER;
+
+    @Override
+    public void setContext(Context context) {
+        super.setContext(context);
+
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        List<UserInfo> users = userManager.getUsers();
+        final int userCount = users.size();
+        for (int i = 0; i < userCount; i++) {
+            UserInfo user = users.get(i);
+            if (!user.isPrimary() && !user.isManagedProfile()) {
+                mSecondaryUserId = user.id;
+                break;
+            }
+        }
+    }
+
+    protected void setStringViaFrontEndApiSetting(int type, String name, String value, int userId) {
+        ContentResolver contentResolver = getContext().getContentResolver();
+
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                Settings.Global.putStringForUser(contentResolver, name, value, userId);
+            } break;
+
+            case SETTING_TYPE_SECURE: {
+                Settings.Secure.putStringForUser(contentResolver, name, value, userId);
+            } break;
+
+            case SETTING_TYPE_SYSTEM: {
+                Settings.System.putStringForUser(contentResolver, name, value, userId);
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected String getStringViaFrontEndApiSetting(int type, String name, int userId) {
+        ContentResolver contentResolver = getContext().getContentResolver();
+
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                return Settings.Global.getStringForUser(contentResolver, name, userId);
+            }
+
+            case SETTING_TYPE_SECURE: {
+                return Settings.Secure.getStringForUser(contentResolver, name, userId);
+            }
+
+            case SETTING_TYPE_SYSTEM: {
+                return Settings.System.getStringForUser(contentResolver, name, userId);
+            }
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected Uri insertStringViaProviderApi(int type, String name, String value,
+            boolean withTableRowUri) {
+        Uri uri = getBaseUriForType(type);
+        if (withTableRowUri) {
+            uri = Uri.withAppendedPath(uri, name);
+        }
+        ContentValues values = new ContentValues();
+        values.put(Settings.NameValueTable.NAME, name);
+        values.put(Settings.NameValueTable.VALUE, value);
+
+        return getContext().getContentResolver().insert(uri, values);
+    }
+
+    protected int deleteStringViaProviderApi(int type, String name) {
+        Uri uri = getBaseUriForType(type);
+        return getContext().getContentResolver().delete(uri, "name=?", new String[]{name});
+    }
+
+    protected int updateStringViaProviderApiSetting(int type, String name, String value) {
+        Uri uri = getBaseUriForType(type);
+        ContentValues values = new ContentValues();
+        values.put(Settings.NameValueTable.NAME, name);
+        values.put(Settings.NameValueTable.VALUE, value);
+        return getContext().getContentResolver().update(uri, values, "name=?",
+                new String[]{name});
+    }
+
+    protected String queryStringViaProviderApi(int type, String name) {
+        return queryStringViaProviderApi(type, name, false);
+    }
+
+    protected String queryStringViaProviderApi(int type, String name, boolean queryStringInQuotes) {
+        Uri uri = getBaseUriForType(type);
+
+        String queryString = queryStringInQuotes ? "(name=?)" : "name=?";
+
+        Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
+                queryString, new String[]{name}, null);
+
+        if (cursor == null) {
+            return null;
+        }
+
+        try {
+            if (cursor.moveToFirst()) {
+                final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+                return cursor.getString(valueColumnIdx);
+            }
+        } finally {
+            cursor.close();
+        }
+
+        return null;
+    }
+
+    protected static Uri getBaseUriForType(int type) {
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                return Settings.Global.CONTENT_URI;
+            }
+
+            case SETTING_TYPE_SECURE: {
+                return Settings.Secure.CONTENT_URI;
+            }
+
+            case SETTING_TYPE_SYSTEM: {
+                return Settings.System.CONTENT_URI;
+            }
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
new file mode 100644
index 0000000..d581f3b
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+* Performance tests for the SettingContentProvider.
+*/
+public class SettingsProviderPerformanceTest extends BaseSettingsProviderTest {
+    private static final String LOG_TAG = "SettingsProviderPerformanceTest";
+
+    private static final int ITERATION_COUNT = 100;
+
+    private static final int MICRO_SECONDS_IN_MILLISECOND = 1000;
+
+    private static final long MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS = 20;
+
+    public void testSetAndGetPerformanceForGlobalViaFrontEndApi() throws Exception {
+        // Start with a clean slate.
+        insertStringViaProviderApi(SETTING_TYPE_GLOBAL,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+
+        final long startTimeMicro = SystemClock.currentTimeMicro();
+
+        try {
+            for (int i = 0; i < ITERATION_COUNT; i++) {
+                // Set the setting to its first value.
+                updateStringViaProviderApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE);
+
+                // Make sure the setting changed.
+                String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
+
+                // Set the setting to its second value.
+                updateStringViaProviderApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE_1);
+
+                // Make sure the setting changed.
+                String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
+            }
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+        }
+
+        final long elapsedTimeMicro = SystemClock.currentTimeMicro() - startTimeMicro;
+
+        final long averageTimePerIterationMillis = (long) ((((float) elapsedTimeMicro)
+                / ITERATION_COUNT) / MICRO_SECONDS_IN_MILLISECOND);
+
+        Log.i(LOG_TAG, "Average time to set and get setting via provider APIs: "
+                + averageTimePerIterationMillis + " ms");
+
+        assertTrue("Setting and getting a settings takes too long.", averageTimePerIterationMillis
+                < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
+    }
+
+    public void testSetAndGetPerformanceForGlobalViaProviderApi() throws Exception {
+        // Start with a clean slate.
+        deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+
+        final long startTimeMicro = SystemClock.currentTimeMicro();
+
+        try {
+            for (int i = 0; i < ITERATION_COUNT; i++) {
+                // Set the setting to its first value.
+                setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE, UserHandle.USER_OWNER);
+
+                // Make sure the setting changed.
+                String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
+
+                // Set the setting to its second value.
+                setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE_1, UserHandle.USER_OWNER);
+
+                // Make sure the setting changed.
+                String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
+            }
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+        }
+
+        final long elapsedTimeMicro = SystemClock.currentTimeMicro() - startTimeMicro;
+
+        final long averageTimePerIterationMillis = (long) ((((float) elapsedTimeMicro)
+                / ITERATION_COUNT) / MICRO_SECONDS_IN_MILLISECOND);
+
+        Log.i(LOG_TAG, "Average time to set and get setting via front-eng APIs: "
+                + averageTimePerIterationMillis + " ms");
+
+        assertTrue("Setting and getting a settings takes too long.", averageTimePerIterationMillis
+                < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
+    }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
new file mode 100644
index 0000000..cbfcbf5
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Tests for the SettingContentProvider.
+ *
+ * Before you run this test you must add a secondary user.
+ */
+public class SettingsProviderTest extends BaseSettingsProviderTest {
+    private static final String LOG_TAG = "SettingsProviderTest";
+
+    private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
+
+    private static final String[] NAME_VALUE_COLUMNS = new String[]{
+            Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
+    };
+
+    private final Object mLock = new Object();
+
+    public void testSetAndGetGlobalViaFrontEndApiForOwnerUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_OWNER);
+    }
+
+    public void testSetAndGetGlobalViaFrontEndApiForNonOwnerUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+            Log.w(LOG_TAG, "No secondary user. Skipping "
+                    + "testSetAndGetGlobalViaFrontEndApiForNonOwnerUser");
+            return;
+        }
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
+    }
+
+    public void testSetAndGetSecureViaFrontEndApiForOwnerUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_OWNER);
+    }
+
+    public void testSetAndGetSecureViaFrontEndApiForNonOwnerUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+            Log.w(LOG_TAG, "No secondary user. Skipping "
+                    + "testSetAndGetSecureViaFrontEndApiForNonOwnerUser");
+            return;
+        }
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
+    }
+
+    public void testSetAndGetSystemViaFrontEndApiForOwnerUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_OWNER);
+    }
+
+    public void testSetAndGetSystemViaFrontEndApiForNonOwnerUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+            Log.w(LOG_TAG, "No secondary user. Skipping "
+                    + "testSetAndGetSystemViaFrontEndApiForNonOwnerUser");
+            return;
+        }
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
+    }
+
+    public void testSetAndGetGlobalViaProviderApi() throws Exception {
+        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testSetAndGetSecureViaProviderApi() throws Exception {
+        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
+    }
+
+    public void testSetAndGetSystemViaProviderApi() throws Exception {
+        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testSelectAllGlobalViaProviderApi() throws Exception {
+        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+        try {
+            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL,
+                    FAKE_SETTING_NAME);
+        } finally {
+            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+        }
+    }
+
+    public void testSelectAllSecureViaProviderApi() throws Exception {
+        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+        try {
+            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE,
+                    FAKE_SETTING_NAME);
+        } finally {
+            deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME);
+        }
+    }
+
+    public void testSelectAllSystemViaProviderApi() throws Exception {
+        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
+        try {
+            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM,
+                    FAKE_SETTING_NAME);
+        } finally {
+            deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+        }
+    }
+
+    public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
+        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
+        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
+    }
+
+    public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
+        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testBulkInsertGlobalViaProviderApi() throws Exception {
+        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testBulkInsertSystemViaProviderApi() throws Exception {
+        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testBulkInsertSecureViaProviderApi() throws Exception {
+        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
+    }
+
+    public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
+        int insertedCount = 0;
+        try {
+            for (; insertedCount < 1200; insertedCount++) {
+                Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
+                insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
+                        String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
+            }
+            fail("Adding app specific settings must be bound.");
+        } catch (Exception e) {
+            for (; insertedCount >= 0; insertedCount--) {
+                Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
+                deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
+                        String.valueOf(insertedCount));
+            }
+        }
+    }
+
+    public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
+        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
+        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
+    }
+
+    public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
+        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
+    }
+
+    private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
+        // Make sure we have a clean slate.
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+
+        try {
+            // Insert the setting.
+            final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, false);
+            Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
+            assertEquals("Did not get expected Uri.", expectUri, uri);
+
+            // Make sure the first setting is there.
+            String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true);
+            assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+        }
+    }
+
+    private void toTestBulkInsertViaProviderApiForType(int type) {
+        // Make sure we have a clean slate.
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+
+        try {
+            Uri uri = getBaseUriForType(type);
+            ContentValues[] allValues = new ContentValues[2];
+
+            // Insert the first setting.
+            ContentValues firstValues = new ContentValues();
+            firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME);
+            firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE);
+            allValues[0] = firstValues;
+
+            // Insert the first setting.
+            ContentValues secondValues = new ContentValues();
+            secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1);
+            secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1);
+            allValues[1] = secondValues;
+
+            // Verify insertion count.
+            final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues);
+            assertSame("Couldn't insert both values", 2, insertCount);
+
+            // Make sure the first setting is there.
+            String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+            assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue);
+
+            // Make sure the second setting is there.
+            String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+            assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue);
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+            deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+        }
+    }
+
+    private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception {
+        // Make sure it is not there.
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+
+        // Now selection should return nothing.
+        String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertNull("Setting should not be present.", value);
+
+        // Insert the setting.
+        Uri uri = insertStringViaProviderApi(type,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+        Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
+        assertEquals("Did not get expected Uri.", expectUri, uri);
+
+        // Now selection should return the setting.
+        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value);
+
+        // Update the setting.
+        final int changeCount = updateStringViaProviderApiSetting(type,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1);
+        assertEquals("Did not get expected change count.", 1, changeCount);
+
+        // Now selection should return the new setting.
+        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value);
+
+        // Delete the setting.
+        final int deletedCount = deleteStringViaProviderApi(type,
+                FAKE_SETTING_NAME);
+        assertEquals("Did not get expected deleted count", 1, deletedCount);
+
+        // Now selection should return nothing.
+        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertNull("Setting should not be present.", value);
+    }
+
+    private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId)
+            throws Exception {
+        try {
+            // Change the setting and assert a successful change.
+            setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, userId);
+        } finally {
+            // Remove the setting.
+            setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId);
+        }
+    }
+
+    private void performSetAndGetSettingTestViaProviderApi(int type)
+            throws Exception {
+        try {
+            // Change the setting and assert a successful change.
+            setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, true);
+        } finally {
+            // Remove the setting.
+            setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null,
+                    true);
+        }
+    }
+
+    private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
+            final String name, final String value, final int userId) throws Exception {
+        setSettingAndAssertSuccessfulChange(new Runnable() {
+            @Override
+            public void run() {
+                setStringViaFrontEndApiSetting(type, name, value, userId);
+            }
+        }, type, name, value, userId);
+    }
+
+    private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
+            final String name, final String value, final boolean withTableRowUri)
+            throws Exception {
+        setSettingAndAssertSuccessfulChange(new Runnable() {
+            @Override
+            public void run() {
+                insertStringViaProviderApi(type, name, value, withTableRowUri);
+            }
+        }, type, name, value, UserHandle.USER_OWNER);
+    }
+
+    private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
+            final String name, final String value, final int userId) throws Exception {
+        ContentResolver contentResolver = getContext().getContentResolver();
+
+        final Uri settingUri = getBaseUriForType(type);
+
+        final AtomicBoolean success = new AtomicBoolean();
+
+        ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+            public void onChange(boolean selfChange, Uri changeUri, int changeId) {
+                Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
+                assertEquals("Wrong change Uri", changeUri, settingUri);
+                assertEquals("Wrong user id", userId, changeId);
+                String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
+                assertEquals("Wrong setting value", value, changeValue);
+
+                success.set(true);
+
+                synchronized (mLock) {
+                    mLock.notifyAll();
+                }
+            }
+        };
+
+        contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
+
+        try {
+            setCommand.run();
+
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            synchronized (mLock) {
+                if (success.get()) {
+                    return;
+                }
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
+                    fail("Could not change setting for "
+                            + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
+                }
+                final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
+                        - elapsedTimeMillis;
+                try {
+                    mLock.wait(remainingTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            contentResolver.unregisterContentObserver(contentObserver);
+        }
+    }
+
+    private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type,
+            String name) {
+        Uri uri = getBaseUriForType(type);
+
+        Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
+                null, null, null);
+
+        if (cursor == null || !cursor.moveToFirst()) {
+            fail("Nothing selected");
+        }
+
+        try {
+            final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+
+            while (cursor.moveToNext()) {
+                String currentName = cursor.getString(nameColumnIdx);
+                if (name.equals(currentName)) {
+                    return;
+                }
+            }
+
+            fail("Not found setting: " + name);
+        } finally {
+            cursor.close();
+        }
+    }
+}
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index 2e95b4e..ed0697e 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -21,5 +21,5 @@
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Hata raporunuzu paylaşmak için hızlıca sola kaydırın"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
-    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu mesajı göster"</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu iletiyi göster"</string>
 </resources>
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 2ff9a28..47ef42a 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -20,6 +20,8 @@
     $(LOCAL_PATH)/res
 LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.keyguard
 
+include frameworks/base/packages/SettingsLib/common.mk
+
 include $(BUILD_PACKAGE)
 
 ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 4cf4f52d..01b2713 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -21,7 +21,8 @@
     android:id="@+id/keyguard_bottom_area"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    >
+    android:outlineProvider="none"
+    android:elevation="5dp" > <!-- Put it above the status bar header -->
 
     <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
         android:id="@+id/keyguard_indication_text"
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index ea2e1e1..0ba3ba3 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -39,6 +39,7 @@
             android:id="@android:id/title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:ellipsize="end"
             android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
 
         <TextView
@@ -58,4 +59,4 @@
         android:scaleType="center"
         android:src="@drawable/ic_qs_cancel" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 8f367a6..26523f9 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -15,7 +15,7 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent" 
+    android:layout_width="match_parent"
     android:layout_height="match_parent">
     <!-- Status Bar Scrim View -->
     <ImageView
@@ -29,9 +29,16 @@
     <!-- Recents View -->
     <com.android.systemui.recents.views.RecentsView
         android:id="@+id/recents_view"
-        android:layout_width="match_parent" 
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:focusable="true" />
+        android:focusable="true">
+        <!-- MultiStack Debug View -->
+        <ViewStub android:id="@+id/multistack_debug_view_stub"
+               android:layout="@layout/recents_multistack_debug"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="left|bottom" />
+    </com.android.systemui.recents.views.RecentsView>
 
     <!-- Empty View -->
     <ViewStub android:id="@+id/empty_view_stub"
diff --git a/packages/SystemUI/res/layout/recents_multistack_debug.xml b/packages/SystemUI/res/layout/recents_multistack_debug.xml
new file mode 100644
index 0000000..6524a54
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_multistack_debug.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="left|bottom"
+    android:orientation="vertical">
+    <Button
+        android:id="@+id/add_stack"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:padding="8dp"
+        android:textSize="20sp"
+        android:textColor="#ffffffff"
+        android:text="@string/recents_multistack_add_stack"
+        android:fontFamily="sans-serif"
+        android:background="#000000"
+        android:alpha="0.5" />
+    <Button
+        android:id="@+id/resize_stack"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:padding="8dp"
+        android:textSize="20sp"
+        android:textColor="#ffffffff"
+        android:text="@string/recents_multistack_resize_stack"
+        android:fontFamily="sans-serif"
+        android:background="#000000"
+        android:alpha="0.5" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml b/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml
new file mode 100644
index 0000000..36e54a0
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:padding="16dp"
+    android:orientation="vertical"
+    android:descendantFocusability="beforeDescendants"
+    android:focusableInTouchMode="true">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <EditText
+            android:id="@+id/inset_left"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Left"
+            android:singleLine="true"
+            android:imeOptions="actionNext"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+        <EditText
+            android:id="@+id/inset_top"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Top"
+            android:singleLine="true"
+            android:imeOptions="actionNext"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+        <EditText
+            android:id="@+id/inset_right"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Right"
+            android:singleLine="true"
+            android:imeOptions="actionNext"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+        <EditText
+            android:id="@+id/inset_bottom"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Bottom"
+            android:singleLine="true"
+            android:imeOptions="actionDone"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index f1d8ad0..53047a3 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -43,6 +43,16 @@
         android:ellipsize="marquee"
         android:fadingEdge="horizontal" />
     <com.android.systemui.recents.views.FixedSizeImageView
+        android:id="@+id/move_task"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginEnd="52dp"
+        android:layout_gravity="center_vertical|end"
+        android:padding="12dp"
+        android:background="@drawable/recents_button_bg"
+        android:src="@drawable/star"
+        android:visibility="gone" />
+    <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/dismiss_task"
         android:layout_width="48dp"
         android:layout_height="48dp"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 428c9f4..79c37e8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellings"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Klaar"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Gekoppel"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Gekoppel via Wi-Fi-assistent"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Gestoor"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Koppel tans …"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"USB-verbinding"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Warmkol"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kon nie <xliff:g id="APP">%s</xliff:g> begin nie."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Maak alle programme toe"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laai tans"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot vol"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e57c5f4..6db37cc 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ተጨማሪ ቅንብሮች"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ተከናውኗል"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ተገናኝቷል"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"ተቀምጧል"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"በማገናኘት ላይ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"በማገናኘት ላይ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"መገናኛ ነጥብ"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ሁሉንም ማመልከቻዎች አሰናብት"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ኃይል በመሙላት ላይ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> እስኪሞላ ድረስ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 44f4948..c3cb56b 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"المزيد من الإعدادات"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"تم"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏تم التوصيل عبر مساعد Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"تم الحفظ"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"جارٍ الاتصال..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"النطاق"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"نقطة اتصال"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"تعذر بدء <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"تجاهل كل التطبيقات"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسيم رأسي"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"تقسيم مخصص"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"جارٍ الشحن"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> حتى الاكتمال"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 7fc379c..40946d3 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -191,10 +191,10 @@
     <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Затваряне на панела."</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повече време."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"По-малко време."</string>
-    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Светкавицата е изключена."</string>
-    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Светкавицата е включена."</string>
-    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Светкавицата се изключи."</string>
-    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Светкавицата се включи."</string>
+    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фенерчето е изключено."</string>
+    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фенерчето е включено."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фенерчето е изключено."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фенерчето е включено."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Функцията за инвертиране на цветовете се изключи."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Функцията за инвертиране на цветовете се включи."</string>
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобилната точка за достъп се изключи."</string>
@@ -262,13 +262,11 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Още настройки"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Установена е връзка"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Установена е връзка чрез помощника за Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Запазено"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Установява се връзка..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетъринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка за достъп"</string>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Известия"</string>
-    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Светкавица"</string>
+    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Фенерче"</string>
     <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Мобилни данни"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Пренос на данни"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Оставащи данни"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Отхвърляне на всички приложения"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Вертикално разделяне"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Персонализирано разделяне"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарежда се"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до пълно зареждане"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 1110310..f02a278 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"আরো সেটিংস"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"সম্পন্ন হয়েছে"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"সংযুক্ত হয়েছে"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"সংরক্ষিত হয়েছে"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"সংযুক্ত হচ্ছে..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"টেদারিং"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"হটস্পট"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"সমস্ত অ্যাপ্লিকেশন খারিজ করুন"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"চার্জ হয়েছে"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"চার্জ হচ্ছে"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"পূর্ণ হতে <xliff:g id="CHARGING_TIME">%s</xliff:g> সময় লাগবে"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ef5986b..c9d7f3e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Més opcions"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Fet"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connectat"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"S\'ha desat"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"S\'està connectant..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ancoratge a xarxa"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Descarta totes les aplicacions"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6235eb1..5f48a85 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Další nastavení"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Hotovo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Připojeno"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Uloženo"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Připojování..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Sdílení datového připojení"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Odstranit všechny aplikace"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíjení"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do plného nabití"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3153d3f..0beb8fb 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Udført"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tilsluttet"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Forbindelse via Wi-Fi-assistent"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Gemt"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Luk alle applikationer"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Oplader"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> indtil fuld opladet"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 3165a3c..b408937 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Weitere Einstellungen"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Fertig"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Verbunden"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Über WLAN-Assistenten verbunden"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Gespeichert"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Verbindung wird hergestellt…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Alle Apps entfernen"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Geteilte Schaltfläche – vertikal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Geteilte Schaltfläche – benutzerdefiniert"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Wird aufgeladen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Voll in <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index e6ea177..97a175a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Περισσότερες ρυθμίσεις"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Τέλος"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Συνδέθηκε"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Αποθηκεύτηκε"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Σύνδεση…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Πρόσδεση"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Σημείο πρόσβασης Wi-Fi"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Παράβλεψη όλων των εφαρμογών"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Κάθετος διαχωρισμός"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Προσαρμοσμένος διαχωρισμός"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Φόρτιση"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> για πλήρη φόρτιση"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 8e46cce..62b93b6 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connected via Wi‑Fi assistant"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Saved"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Dismiss all applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 8e46cce..62b93b6 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connected via Wi‑Fi assistant"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Saved"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Dismiss all applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c788677..f79c5ed 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Más configuraciones"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Listo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conexión por asistente de Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Guardado/a"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Descartar todas las aplicaciones"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3f2fa15..6bd03c90 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Más opciones"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Listo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conectado a través de asistente Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Guardado"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ignorar todas las aplicaciones"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 9c05158..b17eb05 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Rohkem seadeid"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Valmis"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ühendatud"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ühendatud WiFi-abi kaudu"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Salvestatud"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ühenduse loomine ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jagamine"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Leviala"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Loobu kõikidest rakendustest"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikaalne poolitamine"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Kohandatud poolitamine"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laadimine"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Täislaadimiseks kulub <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index e2a81e9..be21e9d 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -159,7 +159,7 @@
     <skip />
     <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 aplikazioen atala garbitu da."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> hasten."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Jakinarazpena baztertu da."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Jakinarazpenen panela."</string>
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Ezarpen gehiago"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Eginda"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Konektatuta"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Gordeta"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Konektatzen…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Konexioa partekatzea"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Sare publikoa"</string>
@@ -281,7 +279,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pantaila-ainguratzea"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Garbitu aplikazio guztiak"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Baztertu aplikazio guztiak"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kargatzen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> falta zaizkio guztiz kargatzeko"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index c50eabf..11021b1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"انجام شد"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏متصل شده از طریق دستیار Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"ذخیره شده"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"در حال اتصال..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"اتصال به اینترنت با تلفن همراه"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"نقطه اتصال"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> شروع نشد."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"رد کردن همه برنامه‌ها"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسیم عمودی"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"سفارشی کردن تقسیم"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"در حال شارژ شدن"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مانده تا شارژ کامل شود"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3208b1b..eac124e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Lisäasetukset"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Valmis"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Yhdistetty"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Tallennetut"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Yhdistetään…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jaettu yhteys"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Hylkää kaikki sovellukset"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ladataan"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> kunnes täynnä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index e6bd1f6..387b621 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Terminé"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connecté"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Enregistré"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès sans fil"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Supprimer toutes les applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charge en cours..."</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargée dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1d91c8a..eda4afb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"OK"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connecté"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connecté via l\'assistant Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Enregistré"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Supprimer toutes les applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"En charge"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargé dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 78a5fbb..9ae9493 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Máis opcións"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Feito"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conectado ao asistente de wifi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Gardado"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ancoraxe á rede"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona wifi"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Rexeitar todas as aplicacións"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dividir en vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dividir de xeito personalizado"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completar a carga"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 411e3c3..82f9ddd 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"और सेटिंग"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट है"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"वाई-फ़ाई सहायक के द्वारा कनेक्‍ट है"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"सहेजा गया"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट हो रहा है..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"सभी ऐप्लिकेशन ख़ारिज करें"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"कस्‍टम रूप से विभाजित करें"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हो रही है"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"पूर्ण होने में <xliff:g id="CHARGING_TIME">%s</xliff:g> शेष"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 1e42832..1a06261 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Više  postavki"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Povezano"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Povezani putem pomoćnika za Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Spremljeno"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Povezivanje..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Žarišna točka"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Odbaci sve aplikacije"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podijeli okomito"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podijeli prilagođeno"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napunjenosti"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ed105d0..bc08adc 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"További beállítások"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Kész"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Csatlakoztatva"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Csatlakozva Wi‑Fi-segéddel"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Mentett"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Csatlakozás…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Megosztás"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Összes alkalmazás elvetése"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Osztott függőleges"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Osztott egyéni"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Töltés"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> a teljes töltöttségig"</string>
@@ -326,7 +330,7 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalomjegyzék elrejtve"</string>
+    <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Az összes törlése"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 6432060..9b673bc 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Հավելյալ կարգավորումներ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Պատրաստ է"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Կապակցված է"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Պահված է"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Միանում է..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Միացում"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Թեժ կետ"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Հեռացնել բոլոր հավելվածները"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Լիցքավորվում է"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Լրիվ լիցքավորմանը մնաց <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index bd0a99f..54f7f46 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -159,7 +159,7 @@
     <skip />
     <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 ditutup."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulai <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan disingkirkan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bayangan pemberitahuan."</string>
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Setelan lainnya"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tersambung"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Terhubung melalui Asisten Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Disimpan"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Menambatkan"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulai <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Tutup semua aplikasi"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pisahkan Vertikal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pisahkan Khusus"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengisi daya"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sampai penuh"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index adcda3f..8fcf8b1 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Fleiri stillingar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Lokið"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tengt"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Tengt í gegnum Wi-Fi aðstoð"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Vistað"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Tengist..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tjóðrun"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Heitur reitur"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Fjarlægja öll forrit"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Lóðrétt skipting"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Sérsniðin skipting"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Fullhlaðin"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Í hleðslu"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> þar til fullri hleðslu er náð"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 21a483f..0668038 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Altre impostazioni"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Fine"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connesso"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connesso tramite assistente Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Salvata"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connessione..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Rimuovi tutte le applicazioni"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisione in verticale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisione personalizzata"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"In carica"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> al termine della carica"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 15bd235..ac7fd18 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"הגדרות נוספות"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"בוצע"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"מחובר"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"נשמר"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"מתחבר..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"שיתוף אינטרנט בין ניידים"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"נקודה לשיתוף אינטרנט"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"לא ניתן היה להפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"סגור את כל האפליקציות"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"פיצול אנכי"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"פיצול מותאם אישית"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"טוען"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> עד למילוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 5b68f86..8c30d58 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"詳細設定"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完了"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"接続済み"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fiアシスタント経由で接続"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"保存済み"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"接続しています..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"テザリング"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"アクセスポイント"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"すべてのアプリケーションを消去"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"縦に分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"分割(カスタム)"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電しています"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"充電完了まで<xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index b6650d0..7262638 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"დამატებითი პარამეტრები"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"დასრულდა"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"დაკავშირებულია"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"დაკავშირებული Wi-Fi თანაშემწით"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"დამახსოვრებულია"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"დაკავშირება..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"მოდემის რეჟიმი"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"წვდომის წერტილი"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-ის გამოძახება ვერ მოხერხდა."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ყველა აპლიკაციის გაუქმება"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ვერტიკალური გაყოფა"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ინდივიდუალური გაყობა"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"მიმდინარეობს დატენვა"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> სრულად დატენვამდე"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 15c4584..a57f71e 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Қосымша параметрлер"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Дайын"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Қосылды"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Сақталды"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Қосылуда…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетеринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Хот-спот"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Барлық қолданбаларды қабылдамау"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Бөлінген тік"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Бөлінген теңшелетін"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зарядталды"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядталуда"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Толғанға дейін <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 28d586a..9741b36 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ការ​កំណត់​ច្រើន​ទៀត"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"រួចរាល់"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"បាន​ភ្ជាប់"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"បាន​រក្សាទុក"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"កំពុង​តភ្ជាប់..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ការ​ភ្ជាប់"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ហតស្ប៉ត"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ទេ។"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"បោះបង់កម្មវិធីទាំងអស់"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"បំបែកបញ្ឈរ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"បំបែកផ្ទាល់ខ្លួន"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"បាន​បញ្ចូល​ថ្ម​​"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"កំពុង​បញ្ចូល​ថ្ម"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> រហូត​ដល់ពេញ"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 4134c11..5bfa66f 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ಮುಗಿದಿದೆ"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"ಉಳಿಸಲಾಗಿದೆ"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ಟೆಥರಿಂಗ್‌"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 549da84..922e4c1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"설정 더보기"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"완료"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"연결됨"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi 도우미를 통해 연결됨"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"저장됨"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"연결 중..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"테더링"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"핫스팟"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"모든 애플리케이션 닫기"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"수직 분할"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"맞춤 분할"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"충전 중"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"완충까지 <xliff:g id="CHARGING_TIME">%s</xliff:g> 남음"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 960541a..6c54cb6 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -287,8 +287,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Дагы жөндөөлөр"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Аткарылды"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Туташкан"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Сакталды"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Туташууда…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетеринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Туташуу чекити"</string>
@@ -307,6 +305,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Бардык колдонмолорду көз жаздымда калтыруу"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Кубатталды"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Кубатталууда"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> толгонго чейин"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 33e98b2..f205d0f 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ແລ້ວໆ"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ເຊື່ອມ​ຕໍ່ແລ້ວ"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"ເຊື່ອມ​ຕໍ່​ຜ່ານ Wi‑Fi ຕົວ​ຊ່ວຍ​ແລ້ວ"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"ບັນທຶກແລ້ວ"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"ກຳລັງເຊື່ອມຕໍ່..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"​ການ​ປ່ອນ​ສັນ​ຍານ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"​ຮັອດ​ສະ​ປອດ"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່​ສາ​ມາດ​ເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ປ່ອຍ​ທຸກ​ແອັບ​ພ​ລິ​ເຄ"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການ​ແຍກ​ລວງ​ຂວາງ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການ​ແຍກ​ລວງ​ຕັ້ງ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການ​ແຍກ​ກຳ​ນົດ​ເອງ"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ກຳລັງສາກໄຟ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ຈຶ່ງ​ຈະ​ເຕັມ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f7a8c00..5318844 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Daugiau nustatymų"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Atlikta"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Prijungtas"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Išsaugota"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Prisijungiama..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Susiejimas"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Viešosios interneto prieigos taškas"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Atsisakyti visų programų"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikalus skaidymas"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tinkintas skaidymas"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kraunamas"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> iki visiško įkrovimo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a9f7110..d94c122 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Vairāk iestatījumu"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gatavs"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Pievienota"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Saglabāts"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Notiek savienojuma izveide…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Piesaiste"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tīklājs"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Noņemt visas lietojumprogrammas"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikāls dalījums"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pielāgots dalījums"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Notiek uzlāde"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> līdz pilnam akumulatoram"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 4686ba5..b606e33 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Повеќе поставки"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Поврзано"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Поврзано преку помошник за Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Зачувано"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Се поврзува..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Поврзување"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка на пристап"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Отфрли ги сите апликации"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"22°"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"22°"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"22°"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Раздели вертикално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Раздели прилагодено"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Наполнета"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Се полни"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> додека не се наполни"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 41f5923..6a65e6d 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"പൂർത്തിയാക്കി"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"കണക്‌റ്റുചെയ്‌തു"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi അസിസ്റ്റന്റ് മുഖേന കണക്‌റ്റുചെയ്തു"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"സംരക്ഷിച്ചു"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"കണക്റ്റുചെയ്യുന്നു..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ടെതറിംഗ്"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ഹോട്ട്‌സ്‌പോട്ട്"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"എല്ലാ അപ്ലിക്കേഷനുകളും നിരസിക്കുക"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്‌ടാനുസൃതമായി വേർതിരിക്കുക"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ചാർജ്ജുചെയ്‌തു"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ചാർജ്ജുചെയ്യുന്നു"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 8f81367..1d53b17 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Өөр тохиргоо"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Дууссан"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Холбогдсон"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Хадгалагдсан"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Холбогдож байна..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Модем болгох"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Сүлжээний цэг"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж чадсангүй."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Бүх програмыг арилгах"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Босоо чиглэлд хуваах"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Хүссэн хэлбэрээр хуваах"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Цэнэглэж байна"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"дүүргэхэд <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index bf7c5a6..dc5f649 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -225,7 +225,7 @@
     <string name="start_dreams" msgid="7219575858348719790">"डेड्रीम"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"इथरनेट"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"विमान मोड"</string>
-    <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब"</string>
+    <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लूटुथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब (<xliff:g id="NUMBER">%d</xliff:g> डिव्हाइसेस)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब बंद"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"कोणतेही जोडलेले डिव्हाइसेस उपलब्ध नाहीत"</string>
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"अधिक सेटिंग्ज"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण झाले"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट केलेले"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"जतन केलेले"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करीत आहे..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"शोधा"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करणे शक्य झाले नाही."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"सर्व अनुप्रयोग डिसमिस करा"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज झाली"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज होत आहे"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण होईपर्यंत"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 5845d59..4188bd5 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Lagi tetapan"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Disambungkan"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Disambungkan melalui Pembantu Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Disimpan"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Penambatan"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tempat liputan"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ketepikan semua aplikasi"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Menegak Terpisah"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tersuai Terpisah"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengecas"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Lagi <xliff:g id="CHARGING_TIME">%s</xliff:g> untuk penuh"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index c8f4c55..46ba92c 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"နောက်ထပ် ဆက်တင်များ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"လုပ်ပြီး"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ချိတ်ဆက်ထား"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်ပြီး၏"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"သိမ်းဆည်းပြီး"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"ဆက်သွယ်နေ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"တွဲချီပေးခြင်း"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ဟော့စပေါ့"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ရှာဖွေရန်"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ကို မစနိုင်ပါ။"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်မည်"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"−"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"..."</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"အားသွင်းပြီး"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"အားသွင်းနေ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ပြည်သည့် အထိ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 60e27ee..9e87307 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere innstillinger"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Ferdig"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tilkoblet"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Koblet til via en Wi-Fi-assistent"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Lagret"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Kobler til …"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tilknytning"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Wi-Fi-sone"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Avvis alle apper"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Lader"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Fulladet om <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 87cbb6f..7ccab6b 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"थप सेटिङहरू"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"भयो"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"जोडिएको"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi-Fi सहायक द्वारा जोडिएको"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"सुरक्षित गरियो"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"जडान हुँदै..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदर गर्दै"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हटस्पट"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"सबै अनुप्रयोगहरू खारेज गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"अनुकूलन विभाजन गर्नुहोस्"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज भयो"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हुँदै"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण नभएसम्म"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 6786a74..4170534 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellingen"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gereed"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Verbonden"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Verbonden via wifi-assistent"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Opgeslagen"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Verbinding maken…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Alle apps sluiten"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verticaal splitsen"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Aangepast splitsen"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Opladen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot volledig opgeladen"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3f2c7fd..72a5944 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Więcej ustawień"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gotowe"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Połączono"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Połączono przez Asystenta Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Zapisano"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Łączę..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Powiązanie"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Punkt dostępu"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Zamknij wszystkie aplikacje"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podziel pionowo"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podziel niestandardowo"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ładowanie"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do pełnego naładowania"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b5b2650..8f854a6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mais definições"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ligado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ligado através do Assistente de Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Guardado(a)"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"A ligar..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Associação"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ignorar todas as aplicações"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"A carregar"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até ficar completa"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c914a50..889d3ec 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mais configurações"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conectado via assistente de Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Salvo"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Dispensar todos os apps"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Carregando"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c84b96f..159d0be 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mai multe setări"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Terminat"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectat"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conexiune realizată printr-un asistent Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Salvat"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Se conectează..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Închideți toate aplicațiile"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divizare pe verticală"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divizare personalizată"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"S-a încărcat"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Se încarcă"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> până la încărcare completă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index cd00556..3ea47ec 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Настройки"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Подключено"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Установлено подключение через Ассистента Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Сохранено"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Соединение..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступа"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Закрыть все приложения"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядка батареи"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до полной зарядки"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 0a54324..a488050 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -159,7 +159,7 @@
     <skip />
     <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>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කරමින්."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්‍රභා කරඇත."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"දැනුම්දීම් ආවරණය."</string>
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"තව සැකසීම්"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"නිමයි"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"සම්බන්ධිත"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"සුරකින ලදි"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"සම්බන්ධ වෙමින්..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ටෙදරින්"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"හොට්ස්පොට්"</string>
@@ -281,7 +279,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"තිර ඇමිණීම"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
-    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"සියලු යෙදුම් අස් කරන්න"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"සියලුම යෙදුම් අස් කරන්න"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"සිරස්ව වෙන් කරන්න"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"අභිමත ලෙස වෙන් කරන්න"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"අරෝපිතයි"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ආරෝපණය වෙමින්"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> සම්පූර්ණ වන තෙක්"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 9fbd73e4..e9ded7c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Ďalšie nastavenia"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Hotovo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Pripojené"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Pripojené pomocou Asistenta Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Uložené"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Pripája sa..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Zdieľanie dátového pripojenia"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Odmietnuť všetky aplikácie"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Rozdeliť zvislé"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Rozdeliť vlastné"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíja sa"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Úplné nabitie o <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e4a2016..89f90e5 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Več nastavitev"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Končano"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Povezava je vzpostavljena"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Shranjeno"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Vzpostavljanje povezave ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internet prek mobilne naprave"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Dostopna točka"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Opusti vse aplikacije"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Razdeli navpično"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Razdeli po meri"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Polnjenje"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napolnjenosti"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f3d7da0..ee907de 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Још подешавања"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Повезан"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Повезано преко Wi‑Fi помоћника"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Сачувано"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Повезује се..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Повезивање"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Хотспот"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Одбаци све апликације"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Подели вертикално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Прилагођено дељење"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуњење"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> док се не напуни"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0e9879a..9b9bda0 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Fler inställningar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Klart"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ansluten"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ansluten via Wi-Fi-assistent"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Sparad"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ansluter ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internetdelning"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Trådlös surfzon"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ta bort alla appar"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laddar"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tills batteriet är fulladdat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 05cd74a..c512731 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mipangilio zaidi"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Nimemaliza"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Imeunganishwa"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Kilichohifadhiwa"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Inaunganisha..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Kusambaza mtandao"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Mtandao-hewa"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ondoa programu zote"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Inachaji"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Imebakisha <xliff:g id="CHARGING_TIME">%s</xliff:g> ijae"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 7556c7b..9a08476 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"அமைப்பில் மாற்று"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"முடிந்தது"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"இணைக்கப்பட்டது"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"சேமிக்கப்பட்டது"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"இணைக்கிறது..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"டெதெரிங்"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ஹாட்ஸ்பாட்"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"எல்லா பயன்பாடுகளையும் விலக்கு"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"சார்ஜ் செய்யப்பட்டது"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"சார்ஜாகிறது"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"முழுவதும் சார்ஜாக <xliff:g id="CHARGING_TIME">%s</xliff:g> ஆகும்"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 7704e85..595a7f6 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"మరిన్ని సెట్టింగ్‌లు"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"పూర్తయింది"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"కనెక్ట్ చేయబడినది"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"సేవ్ చేయబడింది"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"కనెక్ట్ అవుతోంది..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"టీథరింగ్"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"హాట్‌స్పాట్"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"శోధించు"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభించడం సాధ్యపడలేదు."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"అన్ని అనువర్తనాలను తీసివేయి"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ఛార్జ్ చేయబడింది"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"ఛార్జ్ అవుతోంది"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d591d0a..9bc4483 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"การตั้งค่าเพิ่มเติม"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"เสร็จสิ้น"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"เชื่อมต่อ"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"ที่บันทึกไว้"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"กำลังเชื่อมต่อ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"การปล่อยสัญญาณ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ฮอตสปอต"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ไม่สามารถเริ่มใช้ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ปิดแอปพลิเคชันทั้งหมด"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"แยกในแนวตั้ง"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"แยกแบบกำหนดเอง"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"กำลังชาร์จ"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จึงจะเต็ม"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index abe7b53..e1c0fcd 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Marami pang setting"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Tapos na"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Nakakonekta"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Na-save"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Kumokonekta..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Nagte-tether"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"I-dismiss ang lahat ng application"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Custom"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nagcha-charge"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hanggang mapuno"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9bcdc27..29a5879 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -144,7 +144,7 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Kablosuz"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM kart yok."</string>
-    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth İnternet paylaşımı"</string>
+    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth tethering"</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Uçak modu."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Pil yüzdesi: <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistem ayarları."</string>
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Diğer ayarlar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Bitti"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Bağlı"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Kayıtlı"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Bağlanılıyor..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Tüm uygulamaları kapat"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Şarj oluyor"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Tam şarj olmasına <xliff:g id="CHARGING_TIME">%s</xliff:g> kaldı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 68f7daa..3058b94 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Більше налаштувань"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Під’єднано"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Збережено"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"З’єднання…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступу"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Закрити всі додатки"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Заряджається"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"До повного зарядження <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index bc3dbc2..89269ed 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"مزید ترتیبات"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ہو گیا"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"مربوط"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"محفوظ کردہ"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"مربوط ہو رہا ہے…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"مربوط کرنا"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ہاٹ اسپاٹ"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"سبھی ایپلیکیشنز کو برخاست کریں"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"چارج ہوگئی"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"چارج ہو رہی ہے"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مکمل ہونے تک"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 86ad17e..b9941da 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Boshqa sozlamalar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Tayyor"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ulangan"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi yordamchisi orqali ulangan"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Saqlandi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ulanmoqda…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Modem rejimi"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ulanish nuqtasi"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Barcha ilovalarni olib tashlash"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Batareya quvvati to‘ldi"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Quvvat olmoqda"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 506c60a..8f0c1fc 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -159,7 +159,7 @@
     <skip />
     <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">"Đã loại bỏ tất cả các ứng dụng gần đây."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Bắt đầu <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bóng thông báo."</string>
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Cài đặt khác"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Xong"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Đã kết nối"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Đã lưu"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Đang kết nối..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Đang dùng làm điểm truy cập Internet"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Điểm phát sóng"</string>
@@ -281,7 +279,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"khóa màn hình"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
-    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Loại bỏ tất cả các ứng dụng"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Bỏ qua tất cả các ứng dụng"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Phân tách dọc"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tùy chỉnh phân tách"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Đang sạc"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> cho đến khi đầy"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4b39f65..678654b2 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多设置"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"已连接"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"已连接(通过 WLAN 助手)"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"已保存"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"正在连接…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"网络共享"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"热点"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"关闭所有应用"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自定义分割"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充电完成"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"正在充电"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"还需<xliff:g id="CHARGING_TIME">%s</xliff:g>充满"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 50d8489..e35e632 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -161,7 +161,7 @@
     <skip />
     <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>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"已連線"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"已透過 Wi-Fi 小幫手連線"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"已儲存"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"正在連線…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網絡共享"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"熱點"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"關閉所有應用程式"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後完成充電"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 8a50cf9..ac8135b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -161,7 +161,7 @@
     <skip />
     <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>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
@@ -264,8 +264,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"已連線"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"已透過 Wi‑Fi 小幫手連線"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"已儲存"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"連線中..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網路共用"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"無線基地台"</string>
@@ -284,6 +282,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"關閉所有應用程式"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後充飽"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 19e6b49..a91d76c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -262,8 +262,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Izilungiselelo eziningi"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Kwenziwe"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ixhunyiwe"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ixhunywe ngomsizi we-Wi-FI"</string>
-    <string name="quick_settings_saved" msgid="4758747300943481411">"Ilondoloziwe"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Iyaxhuma..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ukusebenzisa njengemodemu"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"I-Hotspot"</string>
@@ -282,6 +280,12 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Cashisa zonke izinhlelo zokusebenza"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Iyashaja"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ize igcwale"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a7783fc..4c0cea8 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,7 +30,7 @@
     <color name="notification_list_shadow_top">#80000000</color>
     <drawable name="recents_callout_line">#99ffffff</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
-    <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
+    <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
@@ -129,4 +129,5 @@
     <color name="segmented_button_selected">#FFFFFFFF</color>
     <color name="segmented_button_unselected">#B3B0BEC5</color><!-- 70% blue grey 200 -->
     <color name="volume_panel_divider">#1FFFFFFF</color><!-- 12% white -->
+    <color name="light_mode_icon_color">#FF616161</color><!-- grey 700 -->
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2659009..8a73fca 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -146,6 +146,9 @@
      before the app can interrupt again. -->
     <integer name="heads_up_default_snooze_length_ms">60000</integer>
 
+    <!-- Minimum display time for a heads up notification, in milliseconds. -->
+    <integer name="heads_up_notification_minimum_time">3000</integer>
+
     <!-- milliseconds before the heads up notification accepts touches. -->
     <integer name="heads_up_sensitivity_delay">700</integer>
 
@@ -241,10 +244,10 @@
     <bool name="doze_pulse_on_notifications">true</bool>
 
     <!-- Doze: when to pulse after a buzzworthy notification arrives -->
-    <string name="doze_pulse_schedule" translatable="false">1s,10s,30s,60s,120s</string>
+    <string name="doze_pulse_schedule" translatable="false">1s,10s,30s,60s</string>
 
     <!-- Doze: maximum number of times the notification pulse schedule can be reset -->
-    <integer name="doze_pulse_schedule_resets">3</integer>
+    <integer name="doze_pulse_schedule_resets">2</integer>
 
     <!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
     <integer name="doze_pickup_vibration_threshold">2000</integer>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 68dc269..aa53a3e 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -40,5 +40,11 @@
     <item type="id" name="notification_power"/>
     <item type="id" name="notification_screenshot"/>
     <item type="id" name="notification_hidden"/>
+
+    <!-- Whether the icon is from a notification for which targetSdk < L -->
+    <item type="id" name="icon_is_pre_L"/>
+
+    <!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
+    <item type="id" name="icon_is_grayscale" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c977db9..6afca8a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -630,10 +630,6 @@
     <string name="quick_settings_done">Done</string>
     <!-- QuickSettings: Control panel: Label for connected device. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_connected">Connected</string>
-    <!-- QuickSettings: Control panel: Label for a connected Wi-Fi access point when the connection is established by a Wi-Fi assistant application. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_connected_via_wfa">Connected via Wi\u2011Fi assistant</string>
-    <!-- QuickSettings: Control panel: Label for saved device or connection. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_saved">Saved</string>
     <!-- QuickSettings: Control panel: Label for connecting device. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_connecting">Connecting...</string>
     <!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
@@ -672,6 +668,19 @@
     <!-- Recents: Dismiss all button. [CHAR LIMIT=NONE] -->
     <string name="recents_dismiss_all_message">Dismiss all applications</string>
 
+    <!-- Recents: MultiStack add stack button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack">+</string>
+    <!-- Recents: MultiStack remove stack button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_remove_stack">-</string>
+    <!-- Recents: MultiStack resize stack button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_resize_stack">[]</string>
+    <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
+    <!-- Recents: MultiStack add stack split vertical radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
+    <!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
+
     <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
     <string name="expanded_header_battery_charged">Charged</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f2b4a69..bf19b8d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -20,7 +20,7 @@
         <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
     </style>
 
-    <style name="RecentsTheme" parent="@android:style/Theme">
+    <style name="RecentsTheme" parent="@android:style/Theme.Material.Light">
         <!-- NoTitle -->
         <item name="android:windowNoTitle">true</item>
         <!-- Misc -->
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 7bdbd0a..f2f087f 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -23,8 +23,12 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.os.BatteryManager;
@@ -56,12 +60,13 @@
     private float mSubpixelSmoothingRight;
     private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
     private float mTextHeight, mWarningTextHeight;
+    private int mIconTint = Color.WHITE;
 
     private int mHeight;
     private int mWidth;
     private String mWarningString;
     private final int mCriticalLevel;
-    private final int mChargeColor;
+    private int mChargeColor;
     private final float[] mBoltPoints;
     private final Path mBoltPath = new Path();
 
@@ -292,11 +297,27 @@
         for (int i=0; i<mColors.length; i+=2) {
             thresh = mColors[i];
             color = mColors[i+1];
-            if (percent <= thresh) return color;
+            if (percent <= thresh) {
+
+                // Respect tinting for "normal" level
+                if (i == mColors.length-2) {
+                    return mIconTint;
+                } else {
+                    return color;
+                }
+            }
         }
         return color;
     }
 
+    public void setIconTint(int tint) {
+        mIconTint = tint;
+        mFramePaint.setColorFilter(new PorterDuffColorFilter(tint, PorterDuff.Mode.SRC_ATOP));
+        mBoltPaint.setColor(tint);
+        mChargeColor = tint;
+        invalidate();
+    }
+
     @Override
     public void draw(Canvas c) {
         BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6df78ac..f3d214f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -489,6 +489,11 @@
         }
 
         @Override
+        public void resetKeyguard() {
+            resetStateLocked();
+        }
+
+        @Override
         public void playTrustedSound() {
             KeyguardViewMediator.this.playTrustedSound();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index 9155102..95ac558 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -190,6 +190,7 @@
         title.setText(item.line1);
         final TextView summary = (TextView) view.findViewById(android.R.id.summary);
         final boolean twoLines = !TextUtils.isEmpty(item.line2);
+        title.setMaxLines(twoLines ? 1 : 2);
         summary.setVisibility(twoLines ? VISIBLE : GONE);
         summary.setText(twoLines ? item.line2 : null);
         view.setMinimumHeight(mContext.getResources() .getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 974235e..4dacacf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -423,7 +423,9 @@
         }
 
         for (TileRecord record : mRecords) {
-            record.tileView.setDual(record.tile.supportsDualTargets());
+            if (record.tileView.setDual(record.tile.supportsDualTargets())) {
+                record.tileView.handleStateChanged(record.tile.getState());
+            }
             if (record.tileView.getVisibility() == GONE) continue;
             final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
             final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index bb353d5..16ae6b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -172,7 +172,7 @@
         }
     }
 
-    public void setDual(boolean dual) {
+    public boolean setDual(boolean dual) {
         final boolean changed = dual != mDual;
         mDual = dual;
         if (changed) {
@@ -199,6 +199,7 @@
         setFocusable(!dual);
         mDivider.setVisibility(dual ? VISIBLE : GONE);
         postInvalidate();
+        return changed;
     }
 
     private void setRipple(RippleDrawable tileBackground) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index bd4dbe6..70746c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import java.util.List;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -24,16 +26,15 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.SignalTileView;
-import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.policy.NetworkController.AccessPointController.AccessPoint;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 
 /** Quick settings tile: Wifi **/
@@ -282,10 +283,10 @@
         }
 
         @Override
-        public void onAccessPointsChanged(final AccessPoint[] accessPoints) {
-            mAccessPoints = accessPoints;
+        public void onAccessPointsChanged(final List<AccessPoint> accessPoints) {
+            mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]);
             updateItems();
-            if (accessPoints != null && accessPoints.length > 0) {
+            if (accessPoints != null && accessPoints.size() > 0) {
                 fireScanStateChanged(false);
             }
         }
@@ -299,7 +300,7 @@
         public void onDetailItemClick(Item item) {
             if (item == null || item.tag == null) return;
             final AccessPoint ap = (AccessPoint) item.tag;
-            if (!ap.isConnected) {
+            if (!ap.isActive()) {
                 if (mWifiController.connect(ap)) {
                     mHost.collapsePanels();
                 }
@@ -326,16 +327,10 @@
                     final AccessPoint ap = mAccessPoints[i];
                     final Item item = new Item();
                     item.tag = ap;
-                    item.icon = ap.iconId;
-                    item.line1 = ap.ssid;
-                    if (ap.isConnected) {
-                        item.line2 = mContext.getString(ap.isConfigured ?
-                                R.string.quick_settings_connected :
-                                R.string.quick_settings_connected_via_wfa);
-                    } else if (ap.networkId >= 0) {
-                        item.line2 = mContext.getString(R.string.quick_settings_saved);
-                    }
-                    item.overlay = ap.hasSecurity
+                    item.icon = mWifiController.getIcon(ap);
+                    item.line1 = ap.getSsid();
+                    item.line2 = ap.getSummary();
+                    item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
                             ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
                             : null;
                     items[i] = item;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index cfd6b40..192acc6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -39,6 +39,8 @@
             public static final boolean EnableSearchLayout = true;
             // Enables the thumbnail alpha on the front-most task
             public static final boolean EnableThumbnailAlphaOnFrontmost = false;
+            // Enables all system stacks to show up in the same recents stack
+            public static final boolean EnableMultiStackToSingleStack = true;
             // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
             // Enables the simulated task affiliations
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 3c75aac..9dd82fc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -24,7 +24,6 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -56,7 +55,6 @@
 import com.android.systemui.recents.views.TaskViewTransform;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -112,6 +110,9 @@
 
         /** Preloads the next task */
         public void run() {
+            // Temporarily skip this if multi stack is enabled
+            if (mConfig.multiStackEnabled) return;
+
             RecentsConfiguration config = RecentsConfiguration.getInstance();
             if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
                 RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -362,13 +363,21 @@
     }
 
     void showRelativeAffiliatedTask(boolean showNextTask) {
+        // Return early if there is no focused stack
+        int focusedStackId = mSystemServicesProxy.getFocusedStack();
+        TaskStack focusedStack = null;
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
         loader.preloadTasks(plan, true /* isTopTaskHome */);
-        TaskStack stack = plan.getTaskStack();
+        if (mConfig.multiStackEnabled) {
+            if (focusedStackId < 0) return;
+            focusedStack = plan.getTaskStack(focusedStackId);
+        } else {
+            focusedStack = plan.getAllTaskStacks().get(0);
+        }
 
-        // Return early if there are no tasks
-        if (stack.getTaskCount() == 0) return;
+        // Return early if there are no tasks in the focused stack
+        if (focusedStack.getTaskCount() == 0) return;
 
         ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
         // Return early if there is no running task (can't determine affiliated tasks in this case)
@@ -377,7 +386,7 @@
         if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
 
         // Find the task in the recents list
-        ArrayList<Task> tasks = stack.getTasks();
+        ArrayList<Task> tasks = focusedStack.getTasks();
         Task toTask = null;
         ActivityOptions launchOpts = null;
         int taskCount = tasks.size();
@@ -399,7 +408,7 @@
                             R.anim.recents_launch_prev_affiliated_task_source);
                 }
                 if (toTaskKey != null) {
-                    toTask = stack.findTaskWithId(toTaskKey.id);
+                    toTask = focusedStack.findTaskWithId(toTaskKey.id);
                 }
                 numAffiliatedTasks = group.getTaskCount();
                 break;
@@ -473,8 +482,9 @@
             // Reload the widget id before we get the task stack bounds
             reloadSearchBarAppWidget(mContext, mSystemServicesProxy);
         }
-        mConfig.getTaskStackBounds(mWindowRect.width(), mWindowRect.height(), mStatusBarHeight,
-                (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), mTaskStackBounds);
+        mConfig.getAvailableTaskStackBounds(mWindowRect.width(), mWindowRect.height(),
+                mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
+                mTaskStackBounds);
         if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
             mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
         } else {
@@ -653,8 +663,25 @@
             // Create a new load plan if onPreloadRecents() was never triggered
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
         }
+
+        // Temporarily skip the transition (use a dummy fade) if multi stack is enabled.
+        // For multi-stack we need to figure out where each of the tasks are going.
+        if (mConfig.multiStackEnabled) {
+            loader.preloadTasks(sInstanceLoadPlan, true);
+            ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
+            TaskStack stack = stacks.get(0);
+            mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true);
+            TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
+                    mDummyStackView.computeStackVisibilityReport();
+            ActivityOptions opts = getUnknownTransitionActivityOptions();
+            startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+                    false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
+            return;
+        }
+
         loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
-        TaskStack stack = sInstanceLoadPlan.getTaskStack();
+        ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
+        TaskStack stack = stacks.get(0);
 
         // Prepare the dummy stack for the transition
         mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 1833e09..b1ac733 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.Dialog;
 import android.app.SearchManager;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
@@ -43,7 +44,6 @@
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.DebugOverlayView;
@@ -75,6 +75,9 @@
     View mEmptyView;
     DebugOverlayView mDebugOverlay;
 
+    // MultiStack debug
+    RecentsMultiStackDialog mMultiStackDebugDialog;
+
     // Search AppWidget
     RecentsAppWidgetHost mAppWidgetHost;
     AppWidgetProviderInfo mSearchAppWidgetInfo;
@@ -190,7 +193,8 @@
         }
 
         // Start loading tasks according to the load plan
-        if (plan.getTaskStack() == null) {
+        ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
+        if (stacks.size() == 0) {
             loader.preloadTasks(plan, mConfig.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
@@ -199,9 +203,7 @@
         loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
-        SpaceNode root = plan.getSpaceNode();
-        ArrayList<TaskStack> stacks = root.getStacks();
-        boolean hasTasks = root.hasTasks();
+        boolean hasTasks = plan.hasTasks();
         if (hasTasks) {
             mRecentsView.setTaskStacks(stacks);
         }
@@ -591,6 +593,40 @@
         }
     }
 
+
+    /**** RecentsMultiStackDialog ****/
+
+    private RecentsMultiStackDialog getMultiStackDebugDialog() {
+        if (mMultiStackDebugDialog == null) {
+            mMultiStackDebugDialog = new RecentsMultiStackDialog(getFragmentManager());
+        }
+        return mMultiStackDebugDialog;
+    }
+
+    @Override
+    public void onMultiStackAddStack() {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showAddStackDialog();
+    }
+
+    @Override
+    public void onMultiStackResizeStack() {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showResizeStackDialog();
+    }
+
+    @Override
+    public void onMultiStackRemoveStack() {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showRemoveStackDialog();
+    }
+
+    @Override
+    public void onMultiStackMoveTask(Task t) {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showMoveTaskDialog(t);
+    }
+
     /**** RecentsView.RecentsViewCallbacks Implementation ****/
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index bc10a48..1736c77 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -134,6 +134,7 @@
     public boolean fakeShadows;
 
     /** Dev options and global settings */
+    public boolean multiStackEnabled;
     public boolean lockToAppEnabled;
     public boolean developerOptionsEnabled;
     public boolean debugModeEnabled;
@@ -294,6 +295,7 @@
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
         lockToAppEnabled = ssp.getSystemSetting(context,
                 Settings.System.LOCK_TO_APP_ENABLED) != 0;
+        multiStackEnabled = "1".equals(ssp.getSystemProperty("overview.enableMultiStack"));
     }
 
     /** Called when the configuration has changed, and we want to reset any configuration specific
@@ -335,8 +337,8 @@
      * Returns the task stack bounds in the current orientation. These bounds do not account for
      * the system insets.
      */
-    public void getTaskStackBounds(int windowWidth, int windowHeight, int topInset, int rightInset,
-                                   Rect taskStackBounds) {
+    public void getAvailableTaskStackBounds(int windowWidth, int windowHeight, int topInset,
+            int rightInset, Rect taskStackBounds) {
         Rect searchBarBounds = new Rect();
         getSearchBarBounds(windowWidth, windowHeight, topInset, searchBarBounds);
         if (isLandscape && hasTransposedSearchBar) {
@@ -353,7 +355,7 @@
      * the system insets.
      */
     public void getSearchBarBounds(int windowWidth, int windowHeight, int topInset,
-                                   Rect searchBarSpaceBounds) {
+            Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
         int searchBarSize = searchBarSpaceHeightPx;
         if (!Constants.DebugFlags.App.EnableSearchLayout || !hasSearchBarAppWidget()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsMultiStackDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsMultiStackDialog.java
new file mode 100644
index 0000000..fdf9d39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsMultiStackDialog.java
@@ -0,0 +1,339 @@
+/*
+ * 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.recents;
+
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.MutableInt;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Toast;
+import com.android.systemui.R;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+
+import java.util.List;
+
+/**
+ * A helper for the dialogs that show when multistack debugging is on.
+ */
+public class RecentsMultiStackDialog extends DialogFragment {
+
+    static final String TAG = "RecentsMultiStackDialog";
+
+    public static final int ADD_STACK_DIALOG = 0;
+    public static final int ADD_STACK_PICK_APP_DIALOG = 1;
+    public static final int REMOVE_STACK_DIALOG = 2;
+    public static final int RESIZE_STACK_DIALOG = 3;
+    public static final int RESIZE_STACK_PICK_STACK_DIALOG = 4;
+    public static final int MOVE_TASK_DIALOG = 5;
+
+    FragmentManager mFragmentManager;
+    int mCurrentDialogType;
+    MutableInt mTargetStackIndex = new MutableInt(0);
+    Task mTaskToMove;
+    SparseArray<ActivityManager.StackInfo> mStacks;
+    List<ResolveInfo> mLauncherActivities;
+    Rect mAddStackRect;
+    Intent mAddStackIntent;
+
+    View mAddStackDialogContent;
+
+    public RecentsMultiStackDialog() {}
+
+    public RecentsMultiStackDialog(FragmentManager mgr) {
+        mFragmentManager = mgr;
+    }
+
+    /** Shows the add-stack dialog. */
+    void showAddStackDialog() {
+        mCurrentDialogType = ADD_STACK_DIALOG;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Creates a new add-stack dialog. */
+    private void createAddStackDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        builder.setTitle("Add Stack - Enter new dimensions");
+        mAddStackDialogContent =
+                inflater.inflate(R.layout.recents_multistack_stack_size_dialog, null, false);
+        Rect windowRect = ssp.getWindowRect();
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_left, windowRect.left);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_top, windowRect.top);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_right, windowRect.right);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_bottom, windowRect.bottom);
+        builder.setView(mAddStackDialogContent);
+        builder.setPositiveButton("Add Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                int left = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_left);
+                int top = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_top);
+                int right = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_right);
+                int bottom = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_bottom);
+                if (bottom <= top || right <= left) {
+                    Toast.makeText(context, "Invalid dimensions", Toast.LENGTH_SHORT).show();
+                    dismiss();
+                    return;
+                }
+
+                // Prompt the user for the app to start
+                dismiss();
+                mCurrentDialogType = ADD_STACK_PICK_APP_DIALOG;
+                mAddStackRect = new Rect(left, top, right, bottom);
+                show(mFragmentManager, TAG);
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Creates a new add-stack pick-app dialog. */
+    private void createAddStackPickAppDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        mLauncherActivities = ssp.getLauncherApps();
+        mAddStackIntent = null;
+        int activityCount = mLauncherActivities.size();
+        CharSequence[] activityNames = new CharSequence[activityCount];
+        for (int i = 0; i < activityCount; i++) {
+            activityNames[i] = ssp.getActivityLabel(mLauncherActivities.get(i).activityInfo);
+        }
+        builder.setTitle("Add Stack - Pick starting app");
+        builder.setSingleChoiceItems(activityNames, -1,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        ActivityInfo ai = mLauncherActivities.get(which).activityInfo;
+                        mAddStackIntent = new Intent(Intent.ACTION_MAIN);
+                        mAddStackIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+                        mAddStackIntent.setComponent(new ComponentName(ai.packageName, ai.name));
+                    }
+                });
+        builder.setPositiveButton("Add Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                // Display 0 = default display
+                ssp.createNewStack(0, mAddStackRect, mAddStackIntent);
+            }
+        });
+        builder.setNegativeButton("Skip", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                // Display 0 = default display
+                ssp.createNewStack(0, mAddStackRect, null);
+            }
+        });
+    }
+
+    /** Shows the resize-stack dialog. */
+    void showResizeStackDialog() {
+        mCurrentDialogType = RESIZE_STACK_PICK_STACK_DIALOG;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Creates a new resize-stack pick-stack dialog. */
+    private void createResizeStackPickStackDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        mStacks = ssp.getAllStackInfos();
+        mTargetStackIndex.value = -1;
+        CharSequence[] stackNames = getAllStacksDescriptions(mStacks, -1, null);
+        builder.setTitle("Resize Stack - Pick stack");
+        builder.setSingleChoiceItems(stackNames, mTargetStackIndex.value,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        mTargetStackIndex.value = which;
+                    }
+                });
+        builder.setPositiveButton("Resize Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (mTargetStackIndex.value != -1) {
+                    // Prompt the user for the new dimensions
+                    dismiss();
+                    mCurrentDialogType = RESIZE_STACK_DIALOG;
+                    show(mFragmentManager, TAG);
+                }
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Creates a new resize-stack dialog. */
+    private void createResizeStackDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        builder.setTitle("Resize Stack - Enter new dimensions");
+        final ActivityManager.StackInfo stack = mStacks.valueAt(mTargetStackIndex.value);
+        mAddStackDialogContent =
+                inflater.inflate(R.layout.recents_multistack_stack_size_dialog, null, false);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_left, stack.bounds.left);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_top, stack.bounds.top);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_right, stack.bounds.right);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_bottom, stack.bounds.bottom);
+        builder.setView(mAddStackDialogContent);
+        builder.setPositiveButton("Resize Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                int left = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_left);
+                int top = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_top);
+                int right = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_right);
+                int bottom = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_bottom);
+                if (bottom <= top || right <= left) {
+                    Toast.makeText(context, "Invalid dimensions", Toast.LENGTH_SHORT).show();
+                    dismiss();
+                    return;
+                }
+                ssp.resizeStack(stack.stackId, new Rect(left, top, right, bottom));
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Shows the remove-stack dialog. */
+    void showRemoveStackDialog() {
+        mCurrentDialogType = REMOVE_STACK_DIALOG;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Shows the move-task dialog. */
+    void showMoveTaskDialog(Task task) {
+        mCurrentDialogType = MOVE_TASK_DIALOG;
+        mTaskToMove = task;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Creates a new move-stack dialog. */
+    private void createMoveTaskDialog(final Context context, LayoutInflater inflater,
+                                AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        mStacks = ssp.getAllStackInfos();
+        mTargetStackIndex.value = -1;
+        CharSequence[] stackNames = getAllStacksDescriptions(mStacks, mTaskToMove.key.stackId,
+                mTargetStackIndex);
+        builder.setTitle("Move Task to Stack");
+        builder.setSingleChoiceItems(stackNames, mTargetStackIndex.value,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        mTargetStackIndex.value = which;
+                    }
+                });
+        builder.setPositiveButton("Move Task", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (mTargetStackIndex.value != -1) {
+                    ActivityManager.StackInfo toStack = mStacks.valueAt(mTargetStackIndex.value);
+                    if (toStack.stackId != mTaskToMove.key.stackId) {
+                        ssp.moveTaskToStack(mTaskToMove.key.id, toStack.stackId, true);
+                        mTaskToMove.setStackId(toStack.stackId);
+                    }
+                }
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Helper to get an integer value from an edit text. */
+    private int getDimensionFromEditText(View container, int id) {
+        String text = ((EditText) container.findViewById(id)).getText().toString();
+        if (text.trim().length() != 0) {
+            return Integer.parseInt(text.trim());
+        }
+        return 0;
+    }
+
+    /** Helper to set an integer value to an edit text. */
+    private void setDimensionInEditText(View container, int id, int value) {
+        ((EditText) container.findViewById(id)).setText("" + value);
+    }
+
+    /** Gets a list of all the stacks. */
+    private CharSequence[] getAllStacksDescriptions(SparseArray<ActivityManager.StackInfo> stacks,
+            int targetStackId, MutableInt indexOfTargetStackId) {
+        int stackCount = stacks.size();
+        CharSequence[] stackNames = new CharSequence[stackCount];
+        for (int i = 0; i < stackCount; i++) {
+            ActivityManager.StackInfo stack = stacks.valueAt(i);
+            Rect b = stack.bounds;
+            String desc = "Stack " + stack.stackId + " / " +
+                    "" + (stack.taskIds.length > 0 ? stack.taskIds.length : "No") + " tasks\n" +
+                    "(" + b.left + ", " + b.top + ")-(" + b.right + ", " + b.bottom + ")\n";
+            stackNames[i] = desc;
+            if (targetStackId != -1 && stack.stackId == targetStackId) {
+                indexOfTargetStackId.value = i;
+            }
+        }
+        return stackNames;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle args) {
+        final Context context = this.getActivity();
+        final SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+        LayoutInflater inflater = getActivity().getLayoutInflater();
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        switch(mCurrentDialogType) {
+            case ADD_STACK_DIALOG:
+                createAddStackDialog(context, inflater, builder, ssp);
+                break;
+            case ADD_STACK_PICK_APP_DIALOG:
+                createAddStackPickAppDialog(context, inflater, builder, ssp);
+                break;
+            case MOVE_TASK_DIALOG:
+                createMoveTaskDialog(context, inflater, builder, ssp);
+                break;
+            case RESIZE_STACK_PICK_STACK_DIALOG:
+                createResizeStackPickStackDialog(context, inflater, builder, ssp);
+                break;
+            case RESIZE_STACK_DIALOG:
+                createResizeStackDialog(context, inflater, builder, ssp);
+                break;
+        }
+        return builder.create();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 237d4f0..72040fe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IActivityContainer;
 import android.app.IActivityManager;
 import android.app.ITaskStackListener;
 import android.app.SearchManager;
@@ -49,10 +50,12 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.SurfaceControl;
@@ -64,6 +67,8 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
@@ -228,6 +233,23 @@
         return null;
     }
 
+    /** Returns a list of all the launcher apps sorted by name. */
+    public List<ResolveInfo> getLauncherApps() {
+        if (mPm == null) return new ArrayList<ResolveInfo>();
+
+        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        List<ResolveInfo> activities = mPm.queryIntentActivities(mainIntent, 0 /* flags */);
+        Collections.sort(activities, new Comparator<ResolveInfo>() {
+            @Override
+            public int compare(ResolveInfo o1, ResolveInfo o2) {
+                return getActivityLabel(o1.activityInfo).compareTo(
+                        getActivityLabel(o2.activityInfo));
+            }
+        });
+        return activities;
+    }
+
     /** Returns whether the recents is currently running */
     public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
             AtomicBoolean isHomeTopMost) {
@@ -250,6 +272,64 @@
         return false;
     }
 
+    /** Create a new stack. */
+    public void createNewStack(int displayId, Rect bounds, Intent activity) {
+        try {
+            IActivityContainer container = mIam.createStackOnDisplay(displayId);
+            if (container != null) {
+                // Resize the stack
+                resizeStack(container.getStackId(), bounds);
+                // Start the new activity on that stack
+                container.startActivity(activity);
+            }
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /** Resizes a stack. */
+    public void resizeStack(int stackId, Rect bounds) {
+        if (mIam == null) return;
+
+        try {
+            mIam.resizeStack(stackId, bounds);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /** Returns the stack info for all stacks. */
+    public SparseArray<ActivityManager.StackInfo> getAllStackInfos() {
+        if (mIam == null) return new SparseArray<ActivityManager.StackInfo>();
+
+        try {
+            SparseArray<ActivityManager.StackInfo> stacks =
+                    new SparseArray<ActivityManager.StackInfo>();
+            List<ActivityManager.StackInfo> infos = mIam.getAllStackInfos();
+            int stackCount = infos.size();
+            for (int i = 0; i < stackCount; i++) {
+                ActivityManager.StackInfo info = infos.get(i);
+                stacks.put(info.stackId, info);
+            }
+            return stacks;
+        } catch (RemoteException e) {
+            e.printStackTrace();
+            return new SparseArray<ActivityManager.StackInfo>();
+        }
+    }
+
+    /** Returns the focused stack id. */
+    public int getFocusedStack() {
+        if (mIam == null) return -1;
+
+        try {
+            return mIam.getFocusedStackId();
+        } catch (RemoteException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
     /** Returns whether the specified task is in the home stack */
     public boolean isInHomeStack(int taskId) {
         if (mAm == null) return false;
@@ -313,7 +393,7 @@
         return thumbnail;
     }
 
-    /** Moves a task to the front with the specified activity options */
+    /** Moves a task to the front with the specified activity options. */
     public void moveTaskToFront(int taskId, ActivityOptions opts) {
         if (mAm == null) return;
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
@@ -326,6 +406,18 @@
         }
     }
 
+    /** Moves a task to another stack. */
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+        if (mIam == null) return;
+        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
+
+        try {
+            mIam.moveTaskToStack(taskId, stackId, toTop);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
     /** Removes the task */
     public void removeTask(int taskId) {
         if (mAm == null) return;
@@ -524,6 +616,13 @@
     }
 
     /**
+     * Returns a system property.
+     */
+    public String getSystemProperty(String key) {
+        return SystemProperties.get(key);
+    }
+
+    /**
      * Returns the window rect.
      */
     public Rect getWindowRect() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 3d25c80..788e473 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -20,9 +20,12 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.SparseArray;
+import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -60,7 +63,7 @@
     SystemServicesProxy mSystemServicesProxy;
 
     List<ActivityManager.RecentTaskInfo> mRawTasks;
-    TaskStack mStack;
+    SparseArray<TaskStack> mStacks = new SparseArray<>();
     HashMap<Task.ComponentNameKey, ActivityInfoHandle> mActivityInfoCache =
             new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
 
@@ -90,21 +93,28 @@
     synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) {
         if (DEBUG) Log.d(TAG, "preloadPlan");
 
+        // This activity info cache will be used for both preloadPlan() and executePlan()
         mActivityInfoCache.clear();
-        mStack = new TaskStack();
+
+        // TODO (multi-display): Currently assume the primary display
+        Rect displayBounds = mSystemServicesProxy.getWindowRect();
 
         Resources res = mContext.getResources();
-        ArrayList<Task> loadedTasks = new ArrayList<Task>();
+        SparseArray<ArrayList<Task>> stacksTasks = new SparseArray<>();
         if (mRawTasks == null) {
             preloadRawTasks(isTopTaskHome);
         }
+        int firstStackId = -1;
         int taskCount = mRawTasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
+            if (firstStackId < 0) {
+                firstStackId = t.stackId;
+            }
 
             // Compose the task key
-            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
-                    t.firstActiveTime, t.lastActiveTime);
+            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
+                    t.userId, t.firstActiveTime, t.lastActiveTime);
 
             // Get an existing activity info handle if possible
             Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
@@ -143,14 +153,42 @@
                     iconFilename);
             task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy, false);
             if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
-            loadedTasks.add(task);
-        }
-        mStack.setTasks(loadedTasks);
-        mStack.createAffiliatedGroupings(mConfig);
 
-        // Assertion
-        if (mStack.getTaskCount() != mRawTasks.size()) {
-            throw new RuntimeException("Loading failed");
+            if (!mConfig.multiStackEnabled ||
+                    Constants.DebugFlags.App.EnableMultiStackToSingleStack) {
+                ArrayList<Task> stackTasks = stacksTasks.get(firstStackId);
+                if (stackTasks == null) {
+                    stackTasks = new ArrayList<Task>();
+                    stacksTasks.put(firstStackId, stackTasks);
+                }
+                stackTasks.add(task);
+            } else {
+                ArrayList<Task> stackTasks = stacksTasks.get(t.stackId);
+                if (stackTasks == null) {
+                    stackTasks = new ArrayList<Task>();
+                    stacksTasks.put(t.stackId, stackTasks);
+                }
+                stackTasks.add(task);
+            }
+        }
+
+        // Initialize the stacks
+        SparseArray<ActivityManager.StackInfo> stackInfos = mSystemServicesProxy.getAllStackInfos();
+        mStacks.clear();
+        int stackCount = stacksTasks.size();
+        for (int i = 0; i < stackCount; i++) {
+            int stackId = stacksTasks.keyAt(i);
+            ActivityManager.StackInfo info = stackInfos.get(stackId);
+            ArrayList<Task> stackTasks = stacksTasks.valueAt(i);
+            TaskStack stack = new TaskStack(stackId);
+            if (Constants.DebugFlags.App.EnableMultiStackToSingleStack) {
+                stack.setBounds(displayBounds, displayBounds);
+            } else {
+                stack.setBounds(info.bounds, displayBounds);
+            }
+            stack.setTasks(stackTasks);
+            stack.createAffiliatedGroupings(mConfig);
+            mStacks.put(stackId, stack);
         }
     }
 
@@ -166,72 +204,93 @@
         Resources res = mContext.getResources();
 
         // Iterate through each of the tasks and load them according to the load conditions.
-        ArrayList<Task> tasks = mStack.getTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
-            Task task = tasks.get(i);
-            Task.TaskKey taskKey = task.key;
+        int stackCount = mStacks.size();
+        for (int j = 0; j < stackCount; j++) {
+            ArrayList<Task> tasks = mStacks.valueAt(j).getTasks();
+            int taskCount = tasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
+                Task task = tasks.get(i);
+                Task.TaskKey taskKey = task.key;
 
-            // Get an existing activity info handle if possible
-            Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
-            ActivityInfoHandle infoHandle;
-            boolean hadCachedActivityInfo = false;
-            if (mActivityInfoCache.containsKey(cnKey)) {
-                infoHandle = mActivityInfoCache.get(cnKey);
-                hadCachedActivityInfo = true;
-            } else {
-                infoHandle = new ActivityInfoHandle();
-            }
-
-            boolean isRunningTask = (task.key.id == opts.runningTaskId);
-            boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
-            boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
-
-            // If requested, skip the running task
-            if (opts.onlyLoadPausedActivities && isRunningTask) {
-                continue;
-            }
-
-            if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
-                if (task.activityIcon == null) {
-                    if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
-                    task.activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
-                            mSystemServicesProxy, res, infoHandle, true);
+                // Get an existing activity info handle if possible
+                Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
+                ActivityInfoHandle infoHandle;
+                boolean hadCachedActivityInfo = false;
+                if (mActivityInfoCache.containsKey(cnKey)) {
+                    infoHandle = mActivityInfoCache.get(cnKey);
+                    hadCachedActivityInfo = true;
+                } else {
+                    infoHandle = new ActivityInfoHandle();
                 }
-            }
-            if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
-                if (task.thumbnail == null || isRunningTask) {
-                    if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
-                    if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy,
-                                true);
-                    } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
-                        loadQueue.addTask(task);
+
+                boolean isRunningTask = (task.key.id == opts.runningTaskId);
+                boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
+                boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
+
+                // If requested, skip the running task
+                if (opts.onlyLoadPausedActivities && isRunningTask) {
+                    continue;
+                }
+
+                if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
+                    if (task.activityIcon == null) {
+                        if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
+                        task.activityIcon = loader.getAndUpdateActivityIcon(taskKey,
+                                t.taskDescription, mSystemServicesProxy, res, infoHandle, true);
                     }
                 }
-            }
+                if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
+                    if (task.thumbnail == null || isRunningTask) {
+                        if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
+                        if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
+                            task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
+                                    mSystemServicesProxy, true);
+                        } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
+                            loadQueue.addTask(task);
+                        }
+                    }
+                }
 
-            // Update the activity info cache
-            if (!hadCachedActivityInfo && infoHandle.info != null) {
-                mActivityInfoCache.put(cnKey, infoHandle);
+                // Update the activity info cache
+                if (!hadCachedActivityInfo && infoHandle.info != null) {
+                    mActivityInfoCache.put(cnKey, infoHandle);
+                }
             }
         }
     }
 
     /**
-     * Composes and returns a TaskStack from the preloaded list of recent tasks.
+     * Returns all TaskStacks from the preloaded list of recent tasks.
      */
-    public TaskStack getTaskStack() {
-        return mStack;
+    public ArrayList<TaskStack> getAllTaskStacks() {
+        ArrayList<TaskStack> stacks = new ArrayList<TaskStack>();
+        int stackCount = mStacks.size();
+        for (int i = 0; i < stackCount; i++) {
+            stacks.add(mStacks.valueAt(i));
+        }
+        // Ensure that we have at least one stack
+        if (stacks.isEmpty()) {
+            stacks.add(new TaskStack());
+        }
+        return stacks;
     }
 
     /**
-     * Composes and returns a SpaceNode from the preloaded list of recent tasks.
+     * Returns a specific TaskStack from the preloaded list of recent tasks.
      */
-    public SpaceNode getSpaceNode() {
-        SpaceNode node = new SpaceNode();
-        node.setStack(mStack);
-        return node;
+    public TaskStack getTaskStack(int stackId) {
+        return mStacks.get(stackId);
+    }
+
+    /** Returns whether there are any tasks in any stacks. */
+    public boolean hasTasks() {
+        int stackCount = mStacks.size();
+        for (int i = 0; i < stackCount; i++) {
+            if (mStacks.valueAt(i).getTaskCount() > 0) {
+                return true;
+            }
+        }
+        return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
deleted file mode 100644
index 831698a..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.graphics.Rect;
-
-import java.util.ArrayList;
-
-
-/**
- * The full recents space is partitioned using a BSP into various nodes that define where task
- * stacks should be placed.
- */
-public class SpaceNode {
-    /* BSP node callbacks */
-    public interface SpaceNodeCallbacks {
-        /** Notifies when a node is added */
-        public void onSpaceNodeAdded(SpaceNode node);
-        /** Notifies when a node is measured */
-        public void onSpaceNodeMeasured(SpaceNode node, Rect rect);
-    }
-
-    SpaceNode mStartNode;
-    SpaceNode mEndNode;
-
-    TaskStack mStack;
-
-    public SpaceNode() {
-        // Do nothing
-    }
-
-    /** Sets the current stack for this space node */
-    public void setStack(TaskStack stack) {
-        mStack = stack;
-    }
-
-    /** Returns the task stack (not null if this is a leaf) */
-    TaskStack getStack() {
-        return mStack;
-    }
-
-    /** Returns whether there are any tasks in any stacks below this node. */
-    public boolean hasTasks() {
-        return (mStack.getTaskCount() > 0) ||
-                (mStartNode != null && mStartNode.hasTasks()) ||
-                (mEndNode != null && mEndNode.hasTasks());
-    }
-
-    /** Returns whether this is a leaf node */
-    boolean isLeafNode() {
-        return (mStartNode == null) && (mEndNode == null);
-    }
-
-    /** Returns all the descendent task stacks */
-    private void getStacksRec(ArrayList<TaskStack> stacks) {
-        if (isLeafNode()) {
-            stacks.add(mStack);
-        } else {
-            mStartNode.getStacksRec(stacks);
-            mEndNode.getStacksRec(stacks);
-        }
-    }
-    public ArrayList<TaskStack> getStacks() {
-        ArrayList<TaskStack> stacks = new ArrayList<TaskStack>();
-        getStacksRec(stacks);
-        return stacks;
-    }
-}
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 55dfe45..0cd55d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -36,6 +36,9 @@
         public void onTaskDataLoaded();
         /* Notifies when a task has been unbound */
         public void onTaskDataUnloaded();
+
+        /* Notifies when a task's stack id has changed. */
+        public void onMultiStackDebugTaskStackIdChanged();
     }
 
     /** The ComponentNameKey represents the unique primary key for a component
@@ -68,14 +71,17 @@
     public static class TaskKey {
         final ComponentNameKey mComponentNameKey;
         public final int id;
+        public int stackId;
         public final Intent baseIntent;
         public final int userId;
         public long firstActiveTime;
         public long lastActiveTime;
 
-        public TaskKey(int id, Intent intent, int userId, long firstActiveTime, long lastActiveTime) {
+        public TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime,
+                long lastActiveTime) {
             mComponentNameKey = new ComponentNameKey(intent.getComponent(), userId);
             this.id = id;
+            this.stackId = stackId;
             this.baseIntent = intent;
             this.userId = userId;
             this.firstActiveTime = firstActiveTime;
@@ -92,18 +98,19 @@
             if (!(o instanceof TaskKey)) {
                 return false;
             }
-            return id == ((TaskKey) o).id
-                    && userId == ((TaskKey) o).userId;
+            TaskKey otherKey = (TaskKey) o;
+            return id == otherKey.id && stackId == otherKey.stackId && userId == otherKey.userId;
         }
 
         @Override
         public int hashCode() {
-            return (id << 5) + userId;
+            return Objects.hash(id, stackId, userId);
         }
 
         @Override
         public String toString() {
             return "Task.Key: " + id + ", "
+                    + "s: " + stackId + ", "
                     + "u: " + userId + ", "
                     + "lat: " + lastActiveTime + ", "
                     + baseIntent.getComponent().getPackageName();
@@ -180,6 +187,14 @@
         this.group = group;
     }
 
+    /** Updates the stack id of this task. */
+    public void setStackId(int stackId) {
+        key.stackId = stackId;
+        if (mCb != null) {
+            mCb.onMultiStackDebugTaskStackIdChanged();
+        }
+    }
+
     /** Notifies the callback listeners that this task has been loaded */
     public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
         this.applicationIcon = applicationIcon;
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 7f7eee4..5aaea15 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.model;
 
 import android.graphics.Color;
+import android.graphics.Rect;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.NamedCounter;
@@ -173,33 +174,38 @@
         public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
     }
 
-    /** A pair of indices representing the group and task positions in the stack and group. */
-    public static class GroupTaskIndex {
-        public int groupIndex; // Index in the stack
-        public int taskIndex;  // Index in the group
-
-        public GroupTaskIndex() {}
-
-        public GroupTaskIndex(int gi, int ti) {
-            groupIndex = gi;
-            taskIndex = ti;
-        }
-    }
-
     // The task offset to apply to a task id as a group affiliation
     static final int IndividualTaskIdOffset = 1 << 16;
 
+    public final int id;
+    public final Rect stackBounds = new Rect();
+    public final Rect displayBounds = new Rect();
+
     FilteredTaskList mTaskList = new FilteredTaskList();
     TaskStackCallbacks mCb;
 
     ArrayList<TaskGrouping> mGroups = new ArrayList<TaskGrouping>();
     HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<Integer, TaskGrouping>();
 
-    /** Sets the callbacks for this task stack */
+    public TaskStack() {
+        this(0);
+    }
+
+    public TaskStack(int stackId) {
+        id = stackId;
+    }
+
+    /** Sets the callbacks for this task stack. */
     public void setCallbacks(TaskStackCallbacks cb) {
         mCb = cb;
     }
 
+    /** Sets the bounds of this stack. */
+    public void setBounds(Rect stackBounds, Rect displayBounds) {
+        this.stackBounds.set(stackBounds);
+        this.displayBounds.set(displayBounds);
+    }
+
     /** Resets this TaskStack. */
     public void reset() {
         mCb = null;
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 5152150..ea4c4ba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -29,8 +29,10 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
+import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -40,6 +42,7 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -56,13 +59,22 @@
         public void onAllTaskViewsDismissed();
         public void onExitToHomeAnimationTriggered();
         public void onScreenPinningRequest();
+
+        public void onMultiStackAddStack();
+        public void onMultiStackResizeStack();
+        public void onMultiStackRemoveStack();
+        public void onMultiStackMoveTask(Task t);
     }
 
     RecentsConfiguration mConfig;
     LayoutInflater mInflater;
     DebugOverlayView mDebugOverlay;
+    ViewStub mMultiStackDebugStub;
+    View mMultiStackDebugView;
+    RecentsViewLayoutAlgorithm mLayoutAlgorithm;
 
     ArrayList<TaskStack> mStacks;
+    List<TaskStackView> mTaskStackViews = new ArrayList<>();
     View mSearchBar;
     RecentsViewCallbacks mCb;
 
@@ -82,6 +94,29 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mConfig = RecentsConfiguration.getInstance();
         mInflater = LayoutInflater.from(context);
+        mLayoutAlgorithm = new RecentsViewLayoutAlgorithm(mConfig);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        if (!mConfig.multiStackEnabled) return;
+
+        mMultiStackDebugStub = (ViewStub) findViewById(R.id.multistack_debug_view_stub);
+        if (mMultiStackDebugView == null) {
+            mMultiStackDebugView = mMultiStackDebugStub.inflate();
+            mMultiStackDebugView.findViewById(R.id.add_stack).setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mCb.onMultiStackAddStack();
+                }
+            });
+            mMultiStackDebugView.findViewById(R.id.resize_stack).setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mCb.onMultiStackResizeStack();
+                }
+            });
+        }
     }
 
     /** Sets the callbacks */
@@ -98,29 +133,18 @@
     public void setTaskStacks(ArrayList<TaskStack> stacks) {
         int numStacks = stacks.size();
 
-        // Make a list of the stack view children only
-        ArrayList<TaskStackView> stackViews = new ArrayList<TaskStackView>();
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                stackViews.add((TaskStackView) child);
-            }
-        }
-
         // Remove all/extra stack views
         int numTaskStacksToKeep = 0; // Keep no tasks if we are recreating the layout
         if (mConfig.launchedReuseTaskStackViews) {
-            numTaskStacksToKeep = Math.min(childCount, numStacks);
+            numTaskStacksToKeep = Math.min(mTaskStackViews.size(), numStacks);
         }
-        for (int i = stackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
-            removeView(stackViews.get(i));
-            stackViews.remove(i);
+        for (int i = mTaskStackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
+            removeView(mTaskStackViews.remove(i));
         }
 
         // Update the stack views that we are keeping
         for (int i = 0; i < numTaskStacksToKeep; i++) {
-            TaskStackView tsv = stackViews.get(i);
+            TaskStackView tsv = mTaskStackViews.get(i);
             // If onRecentsHidden is not triggered, we need to the stack view again here
             tsv.reset();
             tsv.setStack(stacks.get(i));
@@ -128,47 +152,53 @@
 
         // Add remaining/recreate stack views
         mStacks = stacks;
-        for (int i = stackViews.size(); i < numStacks; i++) {
+        for (int i = mTaskStackViews.size(); i < numStacks; i++) {
             TaskStack stack = stacks.get(i);
             TaskStackView stackView = new TaskStackView(getContext(), stack);
             stackView.setCallbacks(this);
             addView(stackView);
+            mTaskStackViews.add(stackView);
         }
 
         // Enable debug mode drawing on all the stacks if necessary
         if (mConfig.debugModeEnabled) {
-            for (int i = childCount - 1; i >= 0; i--) {
-                View v = getChildAt(i);
-                if (v != mSearchBar) {
-                    TaskStackView stackView = (TaskStackView) v;
-                    stackView.setDebugOverlay(mDebugOverlay);
-                }
+            for (int i = mTaskStackViews.size() - 1; i >= 0; i--) {
+                TaskStackView stackView = mTaskStackViews.get(i);
+                stackView.setDebugOverlay(mDebugOverlay);
             }
         }
 
+        // Bring the debug view to the front
+        if (mMultiStackDebugView != null) {
+            mMultiStackDebugView.bringToFront();
+        }
+
         // Trigger a new layout
         requestLayout();
     }
 
+    /** Gets the list of task views */
+    List<TaskStackView> getTaskStackViews() {
+        return mTaskStackViews;
+    }
+
     /** Launches the focused task from the first stack if possible */
     public boolean launchFocusedTask() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                TaskStack stack = stackView.mStack;
-                // Iterate the stack views and try and find the focused task
-                List<TaskView> taskViews = stackView.getTaskViews();
-                int taskViewCount = taskViews.size();
-                for (int j = 0; j < taskViewCount; j++) {
-                    TaskView tv = taskViews.get(j);
-                    Task task = tv.getTask();
-                    if (tv.isFocusedTask()) {
-                        onTaskViewClicked(stackView, tv, stack, task, false);
-                        return true;
-                    }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            TaskStack stack = stackView.getStack();
+            // Iterate the stack views and try and find the focused task
+            List<TaskView> taskViews = stackView.getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int j = 0; j < taskViewCount; j++) {
+                TaskView tv = taskViews.get(j);
+                Task task = tv.getTask();
+                if (tv.isFocusedTask()) {
+                    onTaskViewClicked(stackView, tv, stack, task, false);
+                    return true;
                 }
             }
         }
@@ -178,24 +208,22 @@
     /** Launches the task that Recents was launched from, if possible */
     public boolean launchPreviousTask() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                TaskStack stack = stackView.mStack;
-                ArrayList<Task> tasks = stack.getTasks();
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            TaskStack stack = stackView.getStack();
+            ArrayList<Task> tasks = stack.getTasks();
 
-                // Find the launch task in the stack
-                if (!tasks.isEmpty()) {
-                    int taskCount = tasks.size();
-                    for (int j = 0; j < taskCount; j++) {
-                        if (tasks.get(j).isLaunchTarget) {
-                            Task task = tasks.get(j);
-                            TaskView tv = stackView.getChildViewForTask(task);
-                            onTaskViewClicked(stackView, tv, stack, task, false);
-                            return true;
-                        }
+            // Find the launch task in the stack
+            if (!tasks.isEmpty()) {
+                int taskCount = tasks.size();
+                for (int j = 0; j < taskCount; j++) {
+                    if (tasks.get(j).isLaunchTarget) {
+                        Task task = tasks.get(j);
+                        TaskView tv = stackView.getChildViewForTask(task);
+                        onTaskViewClicked(stackView, tv, stack, task, false);
+                        return true;
                     }
                 }
             }
@@ -209,13 +237,11 @@
         // to ensure that it runs
         ctx.postAnimationTrigger.increment();
 
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.startEnterRecentsAnimation(ctx);
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.startEnterRecentsAnimation(ctx);
         }
         ctx.postAnimationTrigger.decrement();
     }
@@ -225,13 +251,11 @@
         // We have to increment/decrement the post animation trigger in case there are no children
         // to ensure that it runs
         ctx.postAnimationTrigger.increment();
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.startExitToHomeAnimation(ctx);
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.startExitToHomeAnimation(ctx);
         }
         ctx.postAnimationTrigger.decrement();
 
@@ -287,22 +311,31 @@
         }
 
         Rect taskStackBounds = new Rect();
-        mConfig.getTaskStackBounds(width, height, mConfig.systemInsets.top,
+        mConfig.getAvailableTaskStackBounds(width, height, mConfig.systemInsets.top,
                 mConfig.systemInsets.right, taskStackBounds);
 
-        // Measure each TaskStackView with the full width and height of the window since the 
+        // Measure each TaskStackView with the full width and height of the window since the
         // transition view is a child of that stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar && child.getVisibility() != GONE) {
-                TaskStackView tsv = (TaskStackView) child;
-                // Set the insets to be the top/left inset + search bounds
-                tsv.setStackInsetRect(taskStackBounds);
-                tsv.measure(widthMeasureSpec, heightMeasureSpec);
+        List<TaskStackView> stackViews = getTaskStackViews();
+        List<Rect> stackViewsBounds = mLayoutAlgorithm.computeStackRects(stackViews,
+                taskStackBounds);
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            if (stackView.getVisibility() != GONE) {
+                // We are going to measure the TaskStackView with the whole RecentsView dimensions,
+                // but the actual stack is going to be inset to the bounds calculated by the layout
+                // algorithm
+                stackView.setStackInsetRect(stackViewsBounds.get(i));
+                stackView.measure(widthMeasureSpec, heightMeasureSpec);
             }
         }
 
+        // Measure the multistack debug view
+        if (mMultiStackDebugView != null) {
+            mMultiStackDebugView.measure(width, height);
+        }
+
         setMeasuredDimension(width, height);
     }
 
@@ -322,14 +355,27 @@
 
         // Layout each TaskStackView with the full width and height of the window since the 
         // transition view is a child of that stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar && child.getVisibility() != GONE) {
-                child.layout(left, top, left + child.getMeasuredWidth(),
-                        top + child.getMeasuredHeight());
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            if (stackView.getVisibility() != GONE) {
+                stackView.layout(left, top, left + stackView.getMeasuredWidth(),
+                        top + stackView.getMeasuredHeight());
             }
         }
+
+        // Layout the multistack debug view
+        if (mMultiStackDebugView != null) {
+            Rect taskStackBounds = new Rect();
+            mConfig.getAvailableTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(),
+                    mConfig.systemInsets.top, mConfig.systemInsets.right, taskStackBounds);
+            mMultiStackDebugView.layout(left,
+                    taskStackBounds.bottom - mConfig.systemInsets.bottom -
+                            mMultiStackDebugView.getMeasuredHeight(),
+                    left + mMultiStackDebugView.getMeasuredWidth(),
+                    taskStackBounds.bottom - mConfig.systemInsets.bottom);
+        }
     }
 
     @Override
@@ -343,41 +389,29 @@
     /** Notifies each task view of the user interaction. */
     public void onUserInteraction() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.onUserInteraction();
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.onUserInteraction();
         }
     }
 
     /** Focuses the next task in the first stack view */
     public void focusNextTask(boolean forward) {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.focusNextTask(forward, true);
-                break;
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        if (!stackViews.isEmpty()) {
+            stackViews.get(0).focusNextTask(forward, true);
         }
     }
 
     /** Dismisses the focused task. */
     public void dismissFocusedTask() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.dismissFocusedTask();
-                break;
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        if (!stackViews.isEmpty()) {
+            stackViews.get(0).dismissFocusedTask();
         }
     }
 
@@ -476,9 +510,16 @@
                     }
                 };
             }
-            opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
-                    b, offsetX, offsetY, transform.rect.width(), transform.rect.height(),
-                    sourceView.getHandler(), animStartedListener);
+            if (mConfig.multiStackEnabled) {
+                opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(),
+                        R.anim.recents_from_unknown_enter,
+                        R.anim.recents_from_unknown_exit,
+                        sourceView.getHandler(), animStartedListener);
+            } else {
+                opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
+                        b, offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+                        sourceView.getHandler(), animStartedListener);
+            }
         }
 
         final ActivityOptions launchOpts = opts;
@@ -561,13 +602,11 @@
     /** Final callback after Recents is finally hidden. */
     public void onRecentsHidden() {
         // Notify each task stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.onRecentsHidden();
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.onRecentsHidden();
         }
     }
 
@@ -599,18 +638,23 @@
         }
     }
 
+    @Override
+    public void onMultiStackMoveTask(Task t) {
+        if (mCb != null) {
+            mCb.onMultiStackMoveTask(t);
+        }
+    }
+
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
     public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
         // Propagate this event down to each task stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.onPackagesChanged(monitor, packageName, userId);
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.onPackagesChanged(monitor, packageName, userId);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java
new file mode 100644
index 0000000..eea273c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import android.graphics.Rect;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/* The layout logic for the RecentsView. */
+public class RecentsViewLayoutAlgorithm {
+
+    RecentsConfiguration mConfig;
+
+    public RecentsViewLayoutAlgorithm(RecentsConfiguration config) {
+        mConfig = config;
+    }
+
+    /** Return the relative coordinate given coordinates in another size. */
+    private int getRelativeCoordinate(int availableOffset, int availableSize, int otherCoord, int otherSize) {
+        float relPos = (float) otherCoord / otherSize;
+        return availableOffset + (int) (relPos * availableSize);
+    }
+
+    /**
+     * Computes and returns the bounds that each of the stack views should take up.
+     */
+    List<Rect> computeStackRects(List<TaskStackView> stackViews, Rect availableBounds) {
+        ArrayList<Rect> bounds = new ArrayList<Rect>(stackViews.size());
+        int stackViewsCount = stackViews.size();
+        for (int i = 0; i < stackViewsCount; i++) {
+            TaskStack stack = stackViews.get(i).getStack();
+            Rect sb = stack.stackBounds;
+            Rect db = stack.displayBounds;
+            Rect ab = availableBounds;
+            bounds.add(new Rect(getRelativeCoordinate(ab.left, ab.width(), sb.left, db.width()),
+                    getRelativeCoordinate(ab.top, ab.height(), sb.top, db.height()),
+                    getRelativeCoordinate(ab.left, ab.width(), sb.right, db.width()),
+                    getRelativeCoordinate(ab.top, ab.height(), sb.bottom, db.height())));
+        }
+        return bounds;
+    }
+}
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 290792a..2318319 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -60,6 +60,8 @@
         public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks);
         public void onTaskStackFilterTriggered();
         public void onTaskStackUnfilterTriggered();
+
+        public void onMultiStackMoveTask(Task t);
     }
 
     RecentsConfiguration mConfig;
@@ -149,6 +151,11 @@
         requestLayout();
     }
 
+    /** Returns the task stack. */
+    TaskStack getStack() {
+        return mStack;
+    }
+
     /** Sets the debug overlay */
     public void setDebugOverlay(DebugOverlayView overlay) {
         mDebugOverlay = overlay;
@@ -625,6 +632,11 @@
         return mTouchHandler.onGenericMotionEvent(ev);
     }
 
+    /** Returns the region that touch gestures can be started in. */
+    Rect getTouchableRegion() {
+        return mTaskStackBounds;
+    }
+
     @Override
     public void computeScroll() {
         mStackScroller.computeScroll();
@@ -1326,6 +1338,13 @@
         }
     }
 
+    @Override
+    public void onMultiStackMoveTask(TaskView tv) {
+        if (mCb != null) {
+            mCb.onMultiStackMoveTask(tv.getTask());
+        }
+    }
+
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index ccad2f1..fabc86d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -96,16 +96,6 @@
         }
         return false;
     }
-    /** Bounds the current scroll if necessary, but does not synchronize the stack view with the model. */
-    public boolean boundScrollRaw() {
-        float curScroll = getStackScroll();
-        float newScroll = getBoundedStackScroll(curScroll);
-        if (Float.compare(newScroll, curScroll) != 0) {
-            setStackScrollRaw(newScroll);
-            return true;
-        }
-        return false;
-    }
 
     /** Returns the bounded stack scroll */
     float getBoundedStackScroll(float scroll) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 4a6112c..6cdddc5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -123,6 +123,16 @@
             return false;
         }
 
+        int action = ev.getAction();
+        if (mConfig.multiStackEnabled) {
+            // Check if we are within the bounds of the stack view contents
+            if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
+                if (!mSv.getTouchableRegion().contains((int) ev.getX(), (int) ev.getY())) {
+                    return false;
+                }
+            }
+        }
+
         // Pass through to swipe helper if we are swiping
         mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev);
         if (mInterceptedBySwipeHelper) {
@@ -131,7 +141,6 @@
 
         boolean wasScrolling = mScroller.isScrolling() ||
                 (mScroller.mScrollAnimator != null && mScroller.mScrollAnimator.isRunning());
-        int action = ev.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 // Save the touch down info
@@ -198,6 +207,16 @@
             return false;
         }
 
+        int action = ev.getAction();
+        if (mConfig.multiStackEnabled) {
+            // Check if we are within the bounds of the stack view contents
+            if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
+                if (!mSv.getTouchableRegion().contains((int) ev.getX(), (int) ev.getY())) {
+                    return false;
+                }
+            }
+        }
+
         // Pass through to swipe helper if we are swiping
         if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) {
             return true;
@@ -206,7 +225,6 @@
         // Update the velocity tracker
         initVelocityTrackerIfNotExists();
 
-        int action = ev.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 // Save the touch down info
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 82120bf..098f2f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -45,6 +45,8 @@
         public void onTaskViewDismissed(TaskView tv);
         public void onTaskViewClipStateChanged(TaskView tv);
         public void onTaskViewFocusChanged(TaskView tv, boolean focused);
+
+        public void onMultiStackMoveTask(TaskView tv);
     }
 
     RecentsConfiguration mConfig;
@@ -457,6 +459,11 @@
             .start();
     }
 
+    /** Enables/disables handling touch on this task view. */
+    void setTouchEnabled(boolean enabled) {
+        setOnClickListener(enabled ? this : null);
+    }
+
     /** Animates this task view if the user does not interact with the stack after a certain time. */
     void startNoUserInteractionAnimation() {
         mHeaderView.startNoUserInteractionAnimation();
@@ -667,6 +674,9 @@
             // Rebind any listeners
             mHeaderView.mApplicationIcon.setOnClickListener(this);
             mHeaderView.mDismissButton.setOnClickListener(this);
+            if (mConfig.multiStackEnabled) {
+                mHeaderView.mMoveTaskButton.setOnClickListener(this);
+            }
             mActionButtonView.setOnClickListener(this);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 if (mConfig.developerOptionsEnabled) {
@@ -687,6 +697,9 @@
             // Unbind any listeners
             mHeaderView.mApplicationIcon.setOnClickListener(null);
             mHeaderView.mDismissButton.setOnClickListener(null);
+            if (mConfig.multiStackEnabled) {
+                mHeaderView.mMoveTaskButton.setOnClickListener(null);
+            }
             mActionButtonView.setOnClickListener(null);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 mHeaderView.mApplicationIcon.setOnLongClickListener(null);
@@ -695,9 +708,9 @@
         mTaskDataLoaded = false;
     }
 
-    /** Enables/disables handling touch on this task view. */
-    void setTouchEnabled(boolean enabled) {
-        setOnClickListener(enabled ? this : null);
+    @Override
+    public void onMultiStackDebugTaskStackIdChanged() {
+        mHeaderView.rebindToTask(mTask);
     }
 
     /**** View.OnClickListener Implementation ****/
@@ -717,6 +730,10 @@
                         }
                     } else if (v == mHeaderView.mDismissButton) {
                         dismissTask();
+                    } else if (v == mHeaderView.mMoveTaskButton) {
+                        if (mCb != null) {
+                            mCb.onMultiStackMoveTask(tv);
+                        }
                     }
                 }
             }, 125);
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 e13eed8..b827acc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -56,6 +56,7 @@
     RecentsConfiguration mConfig;
 
     // Header views
+    ImageView mMoveTaskButton;
     ImageView mDismissButton;
     ImageView mApplicationIcon;
     TextView mActivityDescription;
@@ -126,6 +127,10 @@
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+        mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
+        if (mConfig.multiStackEnabled) {
+            mMoveTaskButton.setVisibility(View.VISIBLE);
+        }
 
         // Hide the backgrounds if they are ripple drawables
         if (!Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -188,7 +193,10 @@
             mApplicationIcon.setImageDrawable(t.applicationIcon);
         }
         mApplicationIcon.setContentDescription(t.activityLabel);
-        if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
+        // Always update when multi stack debugging is enabled as the stack id can change
+        if (mConfig.multiStackEnabled) {
+            mActivityDescription.setText("[" + t.key.stackId + "] " + t.activityLabel);
+        } else if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
             mActivityDescription.setText(t.activityLabel);
         }
         // Try and apply the system ui tint
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index eaec8fa..ca54349 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -127,7 +127,6 @@
     protected static final int MSG_SHOW_HEADS_UP = 1028;
     protected static final int MSG_HIDE_HEADS_UP = 1029;
     protected static final int MSG_ESCALATE_HEADS_UP = 1030;
-    protected static final int MSG_DECAY_HEADS_UP = 1031;
 
     protected static final boolean ENABLE_HEADS_UP = true;
     // scores above this threshold should be displayed in heads up mode.
@@ -507,7 +506,6 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
-        mSettingsObserver.onChange(false); // set up
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
                 mSettingsObserver);
@@ -557,6 +555,7 @@
 
         createAndAddWindows();
 
+        mSettingsObserver.onChange(false); // set up
         disable(switches[0], false /* animate */);
         setSystemUiVisibility(switches[1], 0xffffffff);
         topAppWindowChanged(switches[2] != 0);
@@ -773,11 +772,7 @@
         }
 
         if (entry.icon != null) {
-            if (entry.targetSdk >= Build.VERSION_CODES.LOLLIPOP) {
-                entry.icon.setColorFilter(mContext.getResources().getColor(android.R.color.white));
-            } else {
-                entry.icon.setColorFilter(null);
-            }
+            entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
         }
     }
 
@@ -1157,7 +1152,7 @@
         // Do nothing
     }
 
-    public abstract void resetHeadsUpDecayTimer();
+    public abstract void scheduleHeadsUpDecay(long delay);
 
     public abstract void scheduleHeadsUpOpen();
 
@@ -1186,14 +1181,15 @@
         }
 
         if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
-            final boolean allowed = 0 != Settings.Secure.getIntForUser(
+            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
                     mContext.getContentResolver(),
                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
             final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
                     userHandle);
             final boolean allowedByDpm = (dpmFlags
                     & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
-            mUsersAllowingPrivateNotifications.append(userHandle, allowed && allowedByDpm);
+            final boolean allowed = allowedByUser && allowedByDpm;
+            mUsersAllowingPrivateNotifications.append(userHandle, allowed);
             return allowed;
         }
 
@@ -1357,8 +1353,7 @@
 
         PendingIntent contentIntent = sbn.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
-                    isHeadsUp);
+            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey());
             row.setOnClickListener(listener);
         } else {
             row.setOnClickListener(null);
@@ -1519,20 +1514,17 @@
         return true;
     }
 
-    public NotificationClicker makeClicker(PendingIntent intent, String notificationKey,
-            boolean forHun) {
-        return new NotificationClicker(intent, notificationKey, forHun);
+    public NotificationClicker makeClicker(PendingIntent intent, String notificationKey) {
+        return new NotificationClicker(intent, notificationKey);
     }
 
     protected class NotificationClicker implements View.OnClickListener {
         private PendingIntent mIntent;
         private final String mNotificationKey;
-        private boolean mIsHeadsUp;
 
-        public NotificationClicker(PendingIntent intent, String notificationKey, boolean forHun) {
+        public NotificationClicker(PendingIntent intent, String notificationKey) {
             mIntent = intent;
             mNotificationKey = notificationKey;
-            mIsHeadsUp = forHun;
         }
 
         public void onClick(final View v) {
@@ -1545,12 +1537,12 @@
                             mCurrentUserId);
             dismissKeyguardThenExecute(new OnDismissAction() {
                 public boolean onDismiss() {
-                    if (mIsHeadsUp) {
+                    if (mNotificationKey.equals(mHeadsUpNotificationView.getKey())) {
                         // Release the HUN notification to the shade.
                         //
                         // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
                         // become canceled shortly by NoMan, but we can't assume that.
-                        mHeadsUpNotificationView.releaseAndClose();
+                        mHeadsUpNotificationView.releaseImmediately();
                     }
                     new Thread() {
                         @Override
@@ -1897,7 +1889,7 @@
                         && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
 
         final boolean shouldInterrupt = shouldInterrupt(notification);
-        final boolean alertAgain = alertAgain(oldEntry, n);
+        final boolean alertAgain = shouldInterrupt && alertAgain(oldEntry, n);
         boolean updateSuccessful = false;
         if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
                 && publicUnchanged) {
@@ -1920,14 +1912,12 @@
                 }
 
                 if (wasHeadsUp) {
-                    if (shouldInterrupt) {
-                        updateHeadsUpViews(oldEntry, notification);
-                        if (alertAgain) {
-                            resetHeadsUpDecayTimer();
-                        }
-                    } else {
+                    // Release may hang on to the views for a bit, so we should always update them.
+                    updateHeadsUpViews(oldEntry, notification);
+                    mHeadsUpNotificationView.updateNotification(oldEntry, alertAgain);
+                    if (!shouldInterrupt) {
                         // we updated the notification above, so release to build a new shade entry
-                        mHeadsUpNotificationView.releaseAndClose();
+                        mHeadsUpNotificationView.release();
                         return;
                     }
                 } else {
@@ -1950,23 +1940,19 @@
         if (!updateSuccessful) {
             if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
             if (wasHeadsUp) {
-                if (shouldInterrupt) {
-                    if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
-                    Entry newEntry = new Entry(notification, null);
-                    ViewGroup holder = mHeadsUpNotificationView.getHolder();
-                    if (inflateViewsForHeadsUp(newEntry, holder)) {
-                        mHeadsUpNotificationView.showNotification(newEntry);
-                        if (alertAgain) {
-                            resetHeadsUpDecayTimer();
-                        }
-                    } else {
-                        Log.w(TAG, "Couldn't create new updated headsup for package "
-                                + contentView.getPackage());
-                    }
+                if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
+                Entry newEntry = new Entry(notification, null);
+                ViewGroup holder = mHeadsUpNotificationView.getHolder();
+                if (inflateViewsForHeadsUp(newEntry, holder)) {
+                    mHeadsUpNotificationView.updateNotification(newEntry, alertAgain);
                 } else {
+                    Log.w(TAG, "Couldn't create new updated headsup for package "
+                            + contentView.getPackage());
+                }
+                if (!shouldInterrupt) {
                     if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
                     oldEntry.notification = notification;
-                    mHeadsUpNotificationView.releaseAndClose();
+                    mHeadsUpNotificationView.release();
                     return;
                 }
             } else {
@@ -2036,8 +2022,7 @@
         // update the contentIntent
         final PendingIntent contentIntent = notification.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
-                    isHeadsUp);
+            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey());
             entry.row.setOnClickListener(listener);
         } else {
             entry.row.setOnClickListener(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 6310234..7286907 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -17,6 +17,9 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.telephony.SubscriptionInfo;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -55,6 +58,7 @@
     private int mAirplaneContentDescription;
     private String mWifiDescription;
     private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
+    private int mIconTint = Color.WHITE;
 
     ViewGroup mWifiGroup;
     ImageView mVpn, mWifi, mAirplane, mNoSims;
@@ -121,6 +125,7 @@
         }
 
         apply();
+        applyIconTint();
     }
 
     @Override
@@ -187,6 +192,9 @@
         for (int i = 0; i < n; i++) {
             inflatePhoneState(subs.get(i).getSubscriptionId());
         }
+        if (isAttachedToWindow()) {
+            applyIconTint();
+        }
     }
 
     private PhoneState getOrInflateState(int subId) {
@@ -315,6 +323,29 @@
         setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
     }
 
+    public void setIconTint(int tint) {
+        boolean changed = tint != mIconTint;
+        mIconTint = tint;
+        if (changed && isAttachedToWindow()) {
+            applyIconTint();
+        }
+    }
+
+    private void applyIconTint() {
+        setTint(mVpn, mIconTint);
+        setTint(mWifi, mIconTint);
+        setTint(mNoSims, mIconTint);
+        setTint(mAirplane, mIconTint);
+        for (int i = 0; i < mPhoneStates.size(); i++) {
+            mPhoneStates.get(i).setIconTint(mIconTint);
+        }
+    }
+
+    private void setTint(ImageView v, int tint) {
+        v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
+        v.setImageTintList(ColorStateList.valueOf(tint));
+    }
+
     private class PhoneState {
         private final int mSubId;
         private boolean mMobileVisible = false;
@@ -369,6 +400,11 @@
                 event.getText().add(mMobileGroup.getContentDescription());
             }
         }
+
+        public void setIconTint(int tint) {
+            setTint(mMobile, tint);
+            setTint(mMobileType, tint);
+        }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 20dd3e7..d02cd17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -147,6 +147,9 @@
     }
 
     private boolean updateDrawable(boolean withClear) {
+        if (mIcon == null) {
+            return false;
+        }
         Drawable drawable = getIcon(mIcon);
         if (drawable == null) {
             Log.w(TAG, "No icon for slot " + mSlot);
@@ -226,6 +229,12 @@
     }
 
     @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        updateDrawable();
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index fc4d7fe..262d955 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -22,6 +22,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardHostView;
@@ -85,6 +86,7 @@
             mKeyguardView.onResume();
             mKeyguardView.startAppearAnimation();
             mShowingSoon = false;
+            mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
     };
 
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 a2ff64a..7513fc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -112,6 +112,7 @@
     private boolean mQsFullyExpanded;
     private boolean mKeyguardShowing;
     private boolean mDozing;
+    private boolean mDozingOnDown;
     private int mStatusBarState;
     private float mInitialHeightOnTouch;
     private float mInitialTouchX;
@@ -148,7 +149,8 @@
 
     private boolean mBlockTouches;
     private int mNotificationScrimWaitDistance;
-    private boolean mTwoFingerQsExpand;
+    // Used for two finger gesture as well as accessibility shortcut to QS.
+    private boolean mQsExpandImmediate;
     private boolean mTwoFingerQsExpandPossible;
 
     /**
@@ -162,7 +164,7 @@
     private Runnable mLaunchAnimationEndRunnable;
     private boolean mOnlyAffordanceInThisMotion;
     private boolean mKeyguardStatusViewAnimating;
-    private boolean mHeaderAnimatingIn;
+    private boolean mHeaderAnimating;
     private ObjectAnimator mQsContainerAnimator;
     private ValueAnimator mQsSizeChangeAnimator;
 
@@ -221,9 +223,8 @@
         // recompute internal state when qspanel height changes
         mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
-            public void onLayoutChange(View v, int left, int top, int right,
-                    int bottom, int oldLeft, int oldTop, int oldRight,
-                    int oldBottom) {
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
                 final int height = bottom - top;
                 final int oldHeight = oldBottom - oldTop;
                 if (height != oldHeight) {
@@ -475,6 +476,13 @@
         }
     }
 
+    public void expandWithQs() {
+        if (mQsExpansionEnabled) {
+            mQsExpandImmediate = true;
+        }
+        expand();
+    }
+
     @Override
     public void fling(float vel, boolean expand) {
         GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
@@ -500,7 +508,7 @@
         if (mBlockTouches) {
             return false;
         }
-        resetDownStates(event);
+        initDownStates(event);
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
             pointerIndex = 0;
@@ -586,10 +594,11 @@
                 && x < stackScrollerX + mNotificationStackScroller.getWidth();
     }
 
-    private void resetDownStates(MotionEvent event) {
+    private void initDownStates(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             mOnlyAffordanceInThisMotion = false;
             mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
+            mDozingOnDown = isDozing();
         }
     }
 
@@ -634,7 +643,7 @@
         if (mBlockTouches) {
             return false;
         }
-        resetDownStates(event);
+        initDownStates(event);
         if ((!mIsExpanding || mHintAnimationRunning)
                 && !mQsExpanded
                 && mStatusBar.getBarState() != StatusBarState.SHADE) {
@@ -658,7 +667,7 @@
         if (mExpandedHeight != 0) {
             handleQsDown(event);
         }
-        if (!mTwoFingerQsExpand && mQsTracking) {
+        if (!mQsExpandImmediate && mQsTracking) {
             onQsTouch(event);
             if (!mConflictingQsExpansionGesture) {
                 return true;
@@ -675,7 +684,7 @@
         if (mTwoFingerQsExpandPossible && event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
                 && event.getPointerCount() == 2
                 && event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
-            mTwoFingerQsExpand = true;
+            mQsExpandImmediate = true;
             requestPanelHeightUpdate();
 
             // Normally, we start listening when the panel is expanded, but here we need to start
@@ -865,26 +874,28 @@
 
     public void setBarState(int statusBarState, boolean keyguardFadingAway,
             boolean goingToFullShade) {
-        boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD
-                || statusBarState == StatusBarState.SHADE_LOCKED;
-        if (!mKeyguardShowing && keyguardShowing) {
-            setQsTranslation(mQsExpansionHeight);
-            mHeader.setTranslationY(0f);
-        }
+        int oldState = mStatusBarState;
+        boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
         setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
         setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
-        if (goingToFullShade) {
+
+        mStatusBarState = statusBarState;
+        mKeyguardShowing = keyguardShowing;
+
+        if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
+                && statusBarState == StatusBarState.SHADE_LOCKED)) {
             animateKeyguardStatusBarOut();
+            animateHeaderSlidingIn();
+        } else if (oldState == StatusBarState.SHADE_LOCKED
+                && statusBarState == StatusBarState.KEYGUARD) {
+            animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            animateHeaderSlidingOut();
         } else {
             mKeyguardStatusBar.setAlpha(1f);
             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
         }
-        mStatusBarState = statusBarState;
-        mKeyguardShowing = keyguardShowing;
+
         updateQsState();
-        if (goingToFullShade) {
-            animateHeaderSlidingIn();
-        }
     }
 
     private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() {
@@ -906,7 +917,7 @@
             = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            mHeaderAnimatingIn = false;
+            mHeaderAnimating = false;
             mQsContainerAnimator = null;
             mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
         }
@@ -934,10 +945,13 @@
         @Override
         public boolean onPreDraw() {
             getViewTreeObserver().removeOnPreDrawListener(this);
+            long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
+                    ? 0
+                    : mStatusBar.calculateGoingToFullShadeDelay();
             mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
             mHeader.animate()
                     .translationY(0f)
-                    .setStartDelay(mStatusBar.calculateGoingToFullShadeDelay())
+                    .setStartDelay(delay)
                     .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
                     .setInterpolator(mFastOutSlowInInterpolator)
                     .start();
@@ -946,7 +960,7 @@
                     mQsContainer.getTranslationY(),
                     mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
                             - mQsContainer.getTop());
-            mQsContainerAnimator.setStartDelay(mStatusBar.calculateGoingToFullShadeDelay());
+            mQsContainerAnimator.setStartDelay(delay);
             mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
             mQsContainerAnimator.setInterpolator(mFastOutSlowInInterpolator);
             mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
@@ -955,11 +969,33 @@
             return true;
         }
     };
-    
-    private void animateHeaderSlidingIn() {
-        mHeaderAnimatingIn = true;
-        getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
 
+    private void animateHeaderSlidingIn() {
+        mHeaderAnimating = true;
+        getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+    }
+
+    private void animateHeaderSlidingOut() {
+        mHeaderAnimating = true;
+        mHeader.animate().y(-mHeader.getHeight())
+                .setStartDelay(0)
+                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mHeader.animate().setListener(null);
+                        mHeaderAnimating = false;
+                        updateQsState();
+                    }
+                })
+                .start();
+        mQsContainer.animate()
+                .y(-mQsContainer.getHeight())
+                .setStartDelay(0)
+                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .start();
     }
 
     private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
@@ -974,8 +1010,12 @@
     private void animateKeyguardStatusBarOut() {
         mKeyguardStatusBar.animate()
                 .alpha(0f)
-                .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
-                .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
+                .setStartDelay(mStatusBar.isKeyguardFadingAway()
+                        ? mStatusBar.getKeyguardFadingAwayDelay()
+                        : 0)
+                .setDuration(mStatusBar.isKeyguardFadingAway()
+                        ? mStatusBar.getKeyguardFadingAwayDuration() / 2
+                        : StackStateAnimator.ANIMATION_DURATION_STANDARD)
                 .setInterpolator(PhoneStatusBar.ALPHA_OUT)
                 .setUpdateListener(mStatusBarAnimateAlphaListener)
                 .withEndAction(mAnimateKeyguardStatusBarInvisibleEndRunnable)
@@ -990,13 +1030,13 @@
         }
     };
 
-    private void animateKeyguardStatusBarIn() {
+    private void animateKeyguardStatusBarIn(long duration) {
         mKeyguardStatusBar.setVisibility(View.VISIBLE);
         mKeyguardStatusBar.setAlpha(0f);
         mKeyguardStatusBar.animate()
                 .alpha(1f)
                 .setStartDelay(0)
-                .setDuration(DOZE_ANIMATION_DURATION)
+                .setDuration(duration)
                 .setInterpolator(mDozeAnimationInterpolator)
                 .setUpdateListener(mStatusBarAnimateAlphaListener)
                 .start();
@@ -1076,9 +1116,12 @@
     }
 
     private void updateQsState() {
-        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling;
-        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing) ? View.VISIBLE : View.INVISIBLE);
-        mHeader.setExpanded(mKeyguardShowing || (mQsExpanded && !mStackScrollerOverscrolling));
+        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+                ? View.VISIBLE
+                : View.INVISIBLE);
+        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+                || (mQsExpanded && !mStackScrollerOverscrolling));
         mNotificationStackScroller.setScrollingEnabled(
                 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
                         || mQsExpansionFromOverscroll));
@@ -1116,6 +1159,10 @@
         if (mKeyguardShowing) {
             updateHeaderKeyguard();
         }
+        if (mStatusBarState == StatusBarState.SHADE_LOCKED
+                || mStatusBarState == StatusBarState.KEYGUARD) {
+            updateKeyguardBottomAreaAlpha();
+        }
         if (mStatusBarState == StatusBarState.SHADE && mQsExpanded
                 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
             mQsNavbarScrim.setAlpha(getQsExpansionFraction());
@@ -1156,17 +1203,17 @@
     }
 
     private void setQsTranslation(float height) {
-        if (!mHeaderAnimatingIn) {
+        if (!mHeaderAnimating) {
             mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
         }
-        if (mKeyguardShowing) {
+        if (mKeyguardShowing && !mHeaderAnimating) {
             mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
         }
     }
 
     private float calculateQsTopPadding() {
         if (mKeyguardShowing
-                && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
+                && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
 
             // Either QS pushes the notifications down when fully expanded, or QS is fully above the
             // notifications (mostly on tablets). maxNotifications denotes the normal top padding
@@ -1200,7 +1247,7 @@
                 mScrollView.getScrollY(),
                 mAnimateNextTopPaddingChange || animate,
                 mKeyguardShowing
-                        && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted));
+                        && (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted));
         mAnimateNextTopPaddingChange = false;
     }
 
@@ -1313,7 +1360,7 @@
             min = Math.max(min, minHeight);
         }
         int maxHeight;
-        if (mTwoFingerQsExpand || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) {
+        if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) {
             maxHeight = calculatePanelHeightQsExpanded();
         } else {
             maxHeight = calculatePanelHeightShade();
@@ -1328,10 +1375,10 @@
 
     @Override
     protected void onHeightUpdated(float expandedHeight) {
-        if (!mQsExpanded || mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted) {
+        if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
             positionClockAndNotifications();
         }
-        if (mTwoFingerQsExpand || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
+        if (mQsExpandImmediate || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
                 && !mQsExpansionFromOverscroll) {
             float t;
             if (mKeyguardShowing) {
@@ -1471,8 +1518,7 @@
      * Hides the header when notifications are colliding with it.
      */
     private void updateHeader() {
-        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
+        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             updateHeaderKeyguard();
         } else {
             updateHeaderShade();
@@ -1481,15 +1527,14 @@
     }
 
     private void updateHeaderShade() {
-        if (!mHeaderAnimatingIn) {
+        if (!mHeaderAnimating) {
             mHeader.setTranslationY(getHeaderTranslation());
         }
         setQsTranslation(mQsExpansionHeight);
     }
 
     private float getHeaderTranslation() {
-        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
+        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             return 0;
         }
         if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
@@ -1502,30 +1547,42 @@
         return Math.min(0, mNotificationStackScroller.getTranslationY()) / HEADER_RUBBERBAND_FACTOR;
     }
 
-    private void updateHeaderKeyguard() {
-        float alphaNotifications;
+    /**
+     * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
+     *         during swiping up
+     */
+    private float getKeyguardContentsAlpha() {
+        float alpha;
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
 
             // When on Keyguard, we hide the header as soon as the top card of the notification
             // stack scroller is close enough (collision distance) to the bottom of the header.
-            alphaNotifications = getNotificationsTopY()
+            alpha = getNotificationsTopY()
                     /
                     (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance);
         } else {
 
             // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
             // soon as we start translating the stack.
-            alphaNotifications = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
+            alpha = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
         }
-        alphaNotifications = MathUtils.constrain(alphaNotifications, 0, 1);
-        alphaNotifications = (float) Math.pow(alphaNotifications, 0.75);
+        alpha = MathUtils.constrain(alpha, 0, 1);
+        alpha = (float) Math.pow(alpha, 0.75);
+        return alpha;
+    }
+
+    private void updateHeaderKeyguard() {
         float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
-        mKeyguardStatusBar.setAlpha(Math.min(alphaNotifications, alphaQsExpansion)
+        mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
                 * mKeyguardStatusBarAnimateAlpha);
-        mKeyguardBottomArea.setAlpha(Math.min(1 - getQsExpansionFraction(), alphaNotifications));
         setQsTranslation(mQsExpansionHeight);
     }
 
+    private void updateKeyguardBottomAreaAlpha() {
+        mKeyguardBottomArea.setAlpha(
+                Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction()));
+    }
+
     private float getNotificationsTopY() {
         if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
             return getExpandedHeight();
@@ -1555,7 +1612,7 @@
         } else {
             setListening(true);
         }
-        mTwoFingerQsExpand = false;
+        mQsExpandImmediate = false;
         mTwoFingerQsExpandPossible = false;
     }
 
@@ -1573,7 +1630,7 @@
 
     @Override
     protected void setOverExpansion(float overExpansion, boolean isPixels) {
-        if (mConflictingQsExpansionGesture || mTwoFingerQsExpand) {
+        if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
             return;
         }
         if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
@@ -1593,7 +1650,7 @@
     protected void onTrackingStarted() {
         super.onTrackingStarted();
         if (mQsFullyExpanded) {
-            mTwoFingerQsExpand = true;
+            mQsExpandImmediate = true;
         }
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
@@ -1756,6 +1813,7 @@
         mSecureCameraLaunchManager.onSwipingStarted();
         requestDisallowInterceptTouchEvent(true);
         mOnlyAffordanceInThisMotion = true;
+        mQsTracking = false;
     }
 
     @Override
@@ -1817,7 +1875,7 @@
     @Override
     protected boolean fullyExpandedClearAllVisible() {
         return mNotificationStackScroller.isDismissViewNotGone()
-                && mNotificationStackScroller.isScrolledToBottom() && !mTwoFingerQsExpand;
+                && mNotificationStackScroller.isScrolledToBottom() && !mQsExpandImmediate;
     }
 
     @Override
@@ -1897,7 +1955,7 @@
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardStatusBar.setVisibility(View.VISIBLE);
             if (animate) {
-                animateKeyguardStatusBarIn();
+                animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION);
                 mKeyguardBottomArea.startFinishDozeAnimation();
             }
         }
@@ -1947,6 +2005,32 @@
         onEmptySpaceClick(x);
     }
 
+    protected boolean onMiddleClicked() {
+        switch (mStatusBar.getBarState()) {
+            case StatusBarState.KEYGUARD:
+                if (!mDozingOnDown) {
+                    EventLogTags.writeSysuiLockscreenGesture(
+                            EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT,
+                            0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+                    startUnlockHintAnimation();
+                }
+                return true;
+            case StatusBarState.SHADE_LOCKED:
+                if (!mQsExpanded) {
+                    mStatusBar.goToKeyguard();
+                }
+                return true;
+            case StatusBarState.SHADE:
+
+                // This gets called in the middle of the touch handling, where the state is still
+                // that we are tracking the panel. Collapse the panel after this is done.
+                post(mPostCollapseRunnable);
+                return false;
+            default:
+                return true;
+        }
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
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 d86ccee..47034e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -100,7 +100,6 @@
     private boolean mCollapseAfterPeek;
     private boolean mExpanding;
     private boolean mGestureWaitForTouchSlop;
-    private boolean mDozingOnDown;
     private Runnable mPeekRunnable = new Runnable() {
         @Override
         public void run() {
@@ -247,7 +246,6 @@
                 mUpdateFlingOnLayout = false;
                 mPeekTouching = mPanelClosedOnDown;
                 mTouchAboveFalsingThreshold = false;
-                mDozingOnDown = isDozing();
                 if (mVelocityTracker == null) {
                     initVelocityTracker();
                 }
@@ -431,7 +429,6 @@
                 mHasLayoutedSinceDown = false;
                 mUpdateFlingOnLayout = false;
                 mTouchAboveFalsingThreshold = false;
-                mDozingOnDown = isDozing();
                 initVelocityTracker();
                 trackMovement(event);
                 break;
@@ -942,35 +939,14 @@
         }
     }
 
-    private final Runnable mPostCollapseRunnable = new Runnable() {
+    protected final Runnable mPostCollapseRunnable = new Runnable() {
         @Override
         public void run() {
             collapse(false /* delayed */);
         }
     };
-    private boolean onMiddleClicked() {
-        switch (mStatusBar.getBarState()) {
-            case StatusBarState.KEYGUARD:
-                if (!mDozingOnDown) {
-                    EventLogTags.writeSysuiLockscreenGesture(
-                            EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT,
-                            0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
-                    startUnlockHintAnimation();
-                }
-                return true;
-            case StatusBarState.SHADE_LOCKED:
-                mStatusBar.goToKeyguard();
-                return true;
-            case StatusBarState.SHADE:
 
-                // This gets called in the middle of the touch handling, where the state is still
-                // that we are tracking the panel. Collapse the panel after this is done.
-                post(mPostCollapseRunnable);
-                return false;
-            default:
-                return true;
-        }
-    }
+    protected abstract boolean onMiddleClicked();
 
     protected abstract void onEdgeClicked(boolean right);
 
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 25a2f93..ece69d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -32,7 +32,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -50,6 +49,7 @@
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -82,14 +82,12 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
-import android.view.HardwareCanvas;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -97,23 +95,17 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewPropertyAnimator;
 import android.view.ViewStub;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
@@ -172,7 +164,6 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
-import com.android.systemui.statusbar.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
 import com.android.systemui.volume.VolumeComponent;
 
@@ -212,9 +203,6 @@
 
     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
-    private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
-
     private static final int STATUS_OR_NAV_TRANSIENT =
             View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
     private static final long AUTOHIDE_TIMEOUT_MS = 3000;
@@ -238,6 +226,8 @@
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
+    private int mLightModeIconColor;
+
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
@@ -261,8 +251,7 @@
     AccessibilityController mAccessibilityController;
 
     int mNaturalBarHeight = -1;
-    int mIconSize = -1;
-    int mIconHPadding = -1;
+
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
 
@@ -278,23 +267,7 @@
     int mPixelFormat;
     Object mQueueLock = new Object();
 
-    // viewgroup containing the normal contents of the statusbar
-    LinearLayout mStatusBarContents;
-
-    // right-hand icons
-    LinearLayout mSystemIconArea;
-    LinearLayout mSystemIcons;
-
-    // left-hand icons
-    LinearLayout mStatusIcons;
-    LinearLayout mStatusIconsKeyguard;
-
-    // the icons themselves
-    IconMerger mNotificationIcons;
-    View mNotificationIconArea;
-
-    // [+>
-    View mMoreIcon;
+    StatusBarIconController mIconController;
 
     // expanded notifications
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -388,7 +361,7 @@
                 if (!mUseHeadsUp) {
                     Log.d(TAG, "dismissing any existing heads up notification on disable event");
                     setHeadsUpVisibility(false);
-                    mHeadsUpNotificationView.release();
+                    mHeadsUpNotificationView.releaseImmediately();
                     removeHeadsUpView();
                 } else {
                     addHeadsUpView();
@@ -419,7 +392,6 @@
     private boolean mDozing;
     private boolean mScrimSrcModeEnabled;
 
-    private Interpolator mLinearOutSlowIn;
     private Interpolator mLinearInterpolator = new LinearInterpolator();
     private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator();
     public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
@@ -562,6 +534,9 @@
         updateDisplaySize();
         mScrimSrcModeEnabled = mContext.getResources().getBoolean(
                 R.bool.config_status_bar_scrim_behind_use_src);
+        mLightModeIconColor = mContext.getResources().getColor(R.color.light_mode_icon_color,
+                mContext.getTheme());
+
         super.start(); // calls createAndAddWindows()
 
         mMediaSessionManager
@@ -610,8 +585,6 @@
         updateDisplaySize(); // populates mDisplayMetrics
         updateResources();
 
-        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
-
         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                 R.layout.super_status_bar, null);
         mStatusBarWindow.mService = this;
@@ -689,15 +662,6 @@
         // figure out which pixel-format to use for the status bar.
         mPixelFormat = PixelFormat.OPAQUE;
 
-        mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
-        mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons);
-        mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
-        mNotificationIconArea = mStatusBarView.findViewById(R.id.notification_icon_area_inner);
-        mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
-        mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
-        mNotificationIcons.setOverflowIndicator(mMoreIcon);
-        mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
-
         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                 R.id.notification_stack_scroller);
         mStackScroller.setLongPressListener(getNotificationLongClicker());
@@ -741,7 +705,6 @@
         mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
         mHeader.setActivityStarter(this);
         mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
-        mStatusIconsKeyguard = (LinearLayout) mKeyguardStatusBar.findViewById(R.id.statusIcons);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
                 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
@@ -756,6 +719,9 @@
         // set the inital view visibility
         setAreThereNotifications();
 
+        mIconController = new StatusBarIconController(
+                mContext, mStatusBarView, mKeyguardStatusBar, this);
+
         // Background thread for any controllers that need it.
         mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
         mHandlerThread.start();
@@ -1177,49 +1143,17 @@
         mWindowManager.removeView(mHeadsUpNotificationView);
     }
 
-    public void refreshAllStatusBarIcons() {
-        refreshAllIconsForLayout(mStatusIcons);
-        refreshAllIconsForLayout(mStatusIconsKeyguard);
-        refreshAllIconsForLayout(mNotificationIcons);
-    }
-
-    private void refreshAllIconsForLayout(LinearLayout ll) {
-        final int count = ll.getChildCount();
-        for (int n = 0; n < count; n++) {
-            View child = ll.getChildAt(n);
-            if (child instanceof StatusBarIconView) {
-                ((StatusBarIconView) child).updateDrawable();
-            }
-        }
-    }
-
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " icon=" + icon);
-        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
-        view.set(icon);
-        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT, mIconSize));
-        view = new StatusBarIconView(mContext, slot, null);
-        view.set(icon);
-        mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT, mIconSize));
+        mIconController.addSystemIcon(slot, index, viewIndex, icon);
     }
 
     public void updateIcon(String slot, int index, int viewIndex,
             StatusBarIcon old, StatusBarIcon icon) {
-        if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " old=" + old + " icon=" + icon);
-        StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);
-        view.set(icon);
-        view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);
-        view.set(icon);
+        mIconController.updateSystemIcon(slot, index, viewIndex, old, icon);
     }
 
     public void removeIcon(String slot, int index, int viewIndex) {
-        if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
-        mStatusIcons.removeViewAt(viewIndex);
-        mStatusIconsKeyguard.removeViewAt(viewIndex);
+        mIconController.removeSystemIcon(slot, index, viewIndex);
     }
 
     public UserHandle getCurrentUserHandle() {
@@ -1279,33 +1213,6 @@
     }
 
     @Override
-    public void resetHeadsUpDecayTimer() {
-        mHandler.removeMessages(MSG_DECAY_HEADS_UP);
-        if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
-                && mHeadsUpNotificationView.isClearable()) {
-            mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay);
-        }
-    }
-
-    @Override
-    public void scheduleHeadsUpOpen() {
-        mHandler.removeMessages(MSG_SHOW_HEADS_UP);
-        mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
-    }
-
-    @Override
-    public void scheduleHeadsUpClose() {
-        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
-        mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
-    }
-
-    @Override
-    public void scheduleHeadsUpEscalation() {
-        mHandler.removeMessages(MSG_ESCALATE_HEADS_UP);
-        mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
-    }
-
-    @Override
     protected void updateNotificationRanking(RankingMap ranking) {
         mNotificationData.updateRanking(ranking);
         updateNotifications();
@@ -1313,9 +1220,8 @@
 
     @Override
     public void removeNotification(String key, RankingMap ranking) {
-        if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
-                && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) {
-            mHeadsUpNotificationView.clear();
+        if (ENABLE_HEADS_UP) {
+            mHeadsUpNotificationView.removeNotification(key);
         }
 
         StatusBarNotification old = removeNotificationViews(key, ranking);
@@ -1339,7 +1245,6 @@
         if (mNavigationBarView != null) {
             mNavigationBarView.setLayoutDirection(layoutDirection);
         }
-        refreshAllStatusBarIcons();
     }
 
     private void updateShowSearchHoldoff() {
@@ -1480,69 +1385,10 @@
 
     @Override
     protected void updateNotifications() {
-        // TODO: Move this into updateNotificationIcons()?
-        if (mNotificationIcons == null) return;
-
         mNotificationData.filterAndSort();
 
         updateNotificationShade();
-        updateNotificationIcons();
-    }
-
-    private void updateNotificationIcons() {
-        final LinearLayout.LayoutParams params
-            = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
-
-        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
-        final int N = activeNotifications.size();
-        ArrayList<StatusBarIconView> toShow = new ArrayList<>(N);
-
-        // Filter out notifications with low scores.
-        for (int i = 0; i < N; i++) {
-            Entry ent = activeNotifications.get(i);
-            if (ent.notification.getScore() < HIDE_ICONS_BELOW_SCORE &&
-                    !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
-                continue;
-            }
-            toShow.add(ent.icon);
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "refreshing icons: " + toShow.size() +
-                    " notifications, mNotificationIcons=" + mNotificationIcons);
-        }
-
-        ArrayList<View> toRemove = new ArrayList<View>();
-        for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
-            View child = mNotificationIcons.getChildAt(i);
-            if (!toShow.contains(child)) {
-                toRemove.add(child);
-            }
-        }
-
-        final int toRemoveCount = toRemove.size();
-        for (int i = 0; i < toRemoveCount; i++) {
-            mNotificationIcons.removeView(toRemove.get(i));
-        }
-
-        for (int i=0; i<toShow.size(); i++) {
-            View v = toShow.get(i);
-            if (v.getParent() == null) {
-                mNotificationIcons.addView(v, i, params);
-            }
-        }
-
-        // Resort notification icons
-        final int childCount = mNotificationIcons.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View actual = mNotificationIcons.getChildAt(i);
-            StatusBarIconView expected = toShow.get(i);
-            if (actual == expected) {
-                continue;
-            }
-            mNotificationIcons.removeView(expected);
-            mNotificationIcons.addView(expected, i);
-        }
+        mIconController.updateNotificationIcons(mNotificationData);
     }
 
     @Override
@@ -1826,14 +1672,6 @@
         }
     }
 
-    public void showClock(boolean show) {
-        if (mStatusBarView == null) return;
-        View clock = mStatusBarView.findViewById(R.id.clock);
-        if (clock != null) {
-            clock.setVisibility(show ? View.VISIBLE : View.GONE);
-        }
-    }
-
     private int adjustDisableFlags(int state) {
         if (!mLaunchTransitionFadingAway
                 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
@@ -1882,17 +1720,16 @@
         Log.d(TAG, flagdbg.toString());
 
         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-            mSystemIconArea.animate().cancel();
             if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-                animateStatusBarHide(mSystemIconArea, animate);
+                mIconController.hideSystemIconArea(animate);
             } else {
-                animateStatusBarShow(mSystemIconArea, animate);
+                mIconController.showSystemIconArea(animate);
             }
         }
 
         if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
-            boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
-            showClock(show);
+            boolean visible = (state & StatusBarManager.DISABLE_CLOCK) == 0;
+            mIconController.setClockVisibility(visible);
         }
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
@@ -1916,9 +1753,9 @@
 
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                animateStatusBarHide(mNotificationIconArea, animate);
+                mIconController.hideNotificationIconArea(animate);
             } else {
-                animateStatusBarShow(mNotificationIconArea, animate);
+                mIconController.showNotificationIconArea(animate);
             }
         }
 
@@ -1929,60 +1766,6 @@
         }
     }
 
-    /**
-     * Animates {@code v}, a view that is part of the status bar, out.
-     */
-    private void animateStatusBarHide(final View v, boolean animate) {
-        v.animate().cancel();
-        if (!animate) {
-            v.setAlpha(0f);
-            v.setVisibility(View.INVISIBLE);
-            return;
-        }
-        v.animate()
-                .alpha(0f)
-                .setDuration(160)
-                .setStartDelay(0)
-                .setInterpolator(ALPHA_OUT)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        v.setVisibility(View.INVISIBLE);
-                    }
-                });
-    }
-
-    /**
-     * Animates {@code v}, a view that is part of the status bar, in.
-     */
-    private void animateStatusBarShow(View v, boolean animate) {
-        v.animate().cancel();
-        v.setVisibility(View.VISIBLE);
-        if (!animate) {
-            v.setAlpha(1f);
-            return;
-        }
-        v.animate()
-                .alpha(1f)
-                .setDuration(320)
-                .setInterpolator(ALPHA_IN)
-                .setStartDelay(50)
-
-                // We need to clean up any pending end action from animateStatusBarHide if we call
-                // both hide and show in the same frame before the animation actually gets started.
-                // cancel() doesn't really remove the end action.
-                .withEndAction(null);
-
-        // Synchronize the motion with the Keyguard fading if necessary.
-        if (mKeyguardFadingAway) {
-            v.animate()
-                    .setDuration(mKeyguardFadingAwayDuration)
-                    .setInterpolator(mLinearOutSlowIn)
-                    .setStartDelay(mKeyguardFadingAwayDelay)
-                    .start();
-        }
-    }
-
     @Override
     protected BaseStatusBar.H createHandler() {
         return new PhoneStatusBar.H();
@@ -2059,16 +1842,10 @@
                 case MSG_SHOW_HEADS_UP:
                     setHeadsUpVisibility(true);
                     break;
-                case MSG_DECAY_HEADS_UP:
-                    mHeadsUpNotificationView.release();
-                    setHeadsUpVisibility(false);
-                    break;
-                case MSG_HIDE_HEADS_UP:
-                    mHeadsUpNotificationView.release();
-                    setHeadsUpVisibility(false);
-                    break;
                 case MSG_ESCALATE_HEADS_UP:
                     escalateHeadsUp();
+                case MSG_HIDE_HEADS_UP:
+                    mHeadsUpNotificationView.releaseImmediately();
                     setHeadsUpVisibility(false);
                     break;
                 case MSG_LAUNCH_TRANSITION_TIMEOUT:
@@ -2078,11 +1855,41 @@
         }
     }
 
+    @Override
+    public void scheduleHeadsUpDecay(long delay) {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        if (mHeadsUpNotificationView.isClearable()) {
+            mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, delay);
+        }
+    }
+
+    @Override
+    public void scheduleHeadsUpOpen() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        mHandler.removeMessages(MSG_SHOW_HEADS_UP);
+        mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+    }
+
+    @Override
+    public void scheduleHeadsUpClose() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        if (mHeadsUpNotificationView.getVisibility() != View.GONE) {
+            mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+        }
+    }
+
+    @Override
+    public void scheduleHeadsUpEscalation() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        mHandler.removeMessages(MSG_ESCALATE_HEADS_UP);
+        mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+    }
+
     /**  if the interrupting notification had a fullscreen intent, fire it now.  */
     private void escalateHeadsUp() {
         if (mHeadsUpNotificationView.getEntry() != null) {
             final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification;
-            mHeadsUpNotificationView.release();
+            mHeadsUpNotificationView.releaseImmediately();
             final Notification notification = sbn.getNotification();
             if (notification.fullScreenIntent != null) {
                 if (DEBUG)
@@ -2206,8 +2013,7 @@
         // Settings are not available in setup
         if (!mUserSetup) return;
 
-        mNotificationPanel.expand();
-        mNotificationPanel.openQs();
+        mNotificationPanel.expandWithQs();
 
         if (false) postStartTracing();
     }
@@ -2419,6 +2225,16 @@
                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
             }
 
+            if ((diff & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 || sbModeChanged) {
+                boolean isTransparentBar = (mStatusBarMode == MODE_TRANSPARENT
+                        || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
+                boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
+                boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
+
+                mIconController.setIconTint(
+                        (allowLight && light) ? mLightModeIconColor : Color.WHITE);
+
+            }
             // restore the recents bit
             if (wasRecentsVisible) {
                 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
@@ -2668,12 +2484,7 @@
                 mNotificationData.dump(pw, "  ");
             }
 
-            int N = mStatusIcons.getChildCount();
-            pw.println("  system icons: " + N);
-            for (int i=0; i<N; i++) {
-                StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
-                pw.println("    [" + i + "] icon=" + ic);
-            }
+            mIconController.dump(pw);
 
             if (false) {
                 pw.println("see the logcat for a dump of the views we have created.");
@@ -2716,6 +2527,12 @@
         if (mSecurityController != null) {
             mSecurityController.dump(fd, pw, args);
         }
+        if (mHeadsUpNotificationView != null) {
+            mHeadsUpNotificationView.dump(fd, pw, args);
+        } else {
+            pw.println("  mHeadsUpNotificationView: null");
+        }
+
         pw.println("SharedPreferences:");
         for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(),
                 Context.MODE_PRIVATE).getAll().entrySet()) {
@@ -2872,10 +2689,10 @@
         updateDisplaySize(); // populates mDisplayMetrics
 
         updateResources();
-        updateClockSize();
         repositionNavigationBar();
         updateShowSearchHoldoff();
         updateRowStates();
+        mIconController.updateResources();
         mScreenPinningRequest.onConfigurationChanged();
     }
 
@@ -2901,8 +2718,7 @@
         mUserSetupObserver.onChange(false);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
-                mUserSetupObserver,
-                mCurrentUserId);
+                mUserSetupObserver, mCurrentUserId);
     }
 
     private void setHeadsUpVisibility(boolean vis) {
@@ -2914,10 +2730,6 @@
         mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
     }
 
-    public void onHeadsUpDismissed() {
-        mHeadsUpNotificationView.dismiss();
-    }
-
     /**
      * Reload some of our resources when the configuration changes.
      *
@@ -2932,8 +2744,6 @@
         }
 
         loadDimens();
-        mLinearOutSlowIn = AnimationUtils.loadInterpolator(
-                mContext, android.R.interpolator.linear_out_slow_in);
 
         if (mNotificationPanel != null) {
             mNotificationPanel.updateResources();
@@ -2946,34 +2756,14 @@
         }
     }
 
-    private void updateClockSize() {
-        if (mStatusBarView == null) return;
-        TextView clock = (TextView) mStatusBarView.findViewById(R.id.clock);
-        if (clock != null) {
-            FontSizeUtils.updateFontSize(clock, R.dimen.status_bar_clock_size);
-        }
-    }
     protected void loadDimens() {
         final Resources res = mContext.getResources();
 
         mNaturalBarHeight = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
 
-        int newIconSize = res.getDimensionPixelSize(
-            com.android.internal.R.dimen.status_bar_icon_size);
-        int newIconHPadding = res.getDimensionPixelSize(
-            R.dimen.status_bar_icon_padding);
-
-        if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
-//            Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
-            mIconHPadding = newIconHPadding;
-            mIconSize = newIconSize;
-            //reloadAllNotificationIcons(); // reload the tray
-        }
-
         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
 
-        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
         mRowMinHeight =  res.getDimensionPixelSize(R.dimen.notification_min_height);
         mRowMaxHeight =  res.getDimensionPixelSize(R.dimen.notification_max_height);
 
@@ -3179,7 +2969,6 @@
 
     private boolean mDemoModeAllowed;
     private boolean mDemoMode;
-    private DemoStatusIcons mDemoStatusIcons;
 
     @Override
     public void dispatchDemoCommand(String command, Bundle args) {
@@ -3208,10 +2997,8 @@
             dispatchDemoCommandToView(command, args, R.id.battery);
         }
         if (modeChange || command.equals(COMMAND_STATUS)) {
-            if (mDemoStatusIcons == null) {
-                mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
-            }
-            mDemoStatusIcons.dispatchDemoCommand(command, args);
+            mIconController.dispatchDemoCommand(command, args);
+
         }
         if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
             mNetworkController.dispatchDemoCommand(command, args);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
new file mode 100644
index 0000000..5622993
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -0,0 +1,308 @@
+/*
+ * 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.phone;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.BatteryMeterView;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.StatusBarIconView;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controls everything regarding the icons in the status bar and on Keyguard, including, but not
+ * limited to: notification icons, signal cluster, additional status icons, and clock in the status
+ * bar.
+ */
+public class StatusBarIconController {
+
+    private Context mContext;
+    private PhoneStatusBar mPhoneStatusBar;
+    private Interpolator mLinearOutSlowIn;
+    private DemoStatusIcons mDemoStatusIcons;
+    private NotificationColorUtil mNotificationColorUtil;
+
+    private LinearLayout mSystemIconArea;
+    private LinearLayout mStatusIcons;
+    private SignalClusterView mSignalCluster;
+    private LinearLayout mStatusIconsKeyguard;
+    private IconMerger mNotificationIcons;
+    private View mNotificationIconArea;
+    private ImageView mMoreIcon;
+    private BatteryMeterView mBatteryMeterView;
+    private TextView mClock;
+
+    private int mIconSize;
+    private int mIconHPadding;
+
+    private int mIconTint = Color.WHITE;
+
+    public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
+            PhoneStatusBar phoneStatusBar) {
+        mContext = context;
+        mPhoneStatusBar = phoneStatusBar;
+        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+        mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area);
+        mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
+        mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
+        mNotificationIconArea = statusBar.findViewById(R.id.notification_icon_area_inner);
+        mNotificationIcons = (IconMerger) statusBar.findViewById(R.id.notificationIcons);
+        mMoreIcon = (ImageView) statusBar.findViewById(R.id.moreIcon);
+        mNotificationIcons.setOverflowIndicator(mMoreIcon);
+        mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons);
+        mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery);
+        mClock = (TextView) statusBar.findViewById(R.id.clock);
+        mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear_out_slow_in);
+        updateResources();
+    }
+
+    public void updateResources() {
+        mIconSize = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_icon_size);
+        mIconHPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.status_bar_icon_padding);
+        FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size);
+    }
+
+    public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
+        view.set(icon);
+        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+        view = new StatusBarIconView(mContext, slot, null);
+        view.set(icon);
+        mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+        applyIconTint();
+    }
+
+    public void updateSystemIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);
+        view.set(icon);
+        view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);
+        view.set(icon);
+        applyIconTint();
+    }
+
+    public void removeSystemIcon(String slot, int index, int viewIndex) {
+        mStatusIcons.removeViewAt(viewIndex);
+        mStatusIconsKeyguard.removeViewAt(viewIndex);
+    }
+
+    public void updateNotificationIcons(NotificationData notificationData) {
+        final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                mIconSize + 2*mIconHPadding, mPhoneStatusBar.getStatusBarHeight());
+
+        ArrayList<NotificationData.Entry> activeNotifications =
+                notificationData.getActiveNotifications();
+        final int N = activeNotifications.size();
+        ArrayList<StatusBarIconView> toShow = new ArrayList<>(N);
+
+        // Filter out ambient notifications.
+        for (int i = 0; i < N; i++) {
+            NotificationData.Entry ent = activeNotifications.get(i);
+            if (notificationData.isAmbient(ent.key)
+                    && !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
+                continue;
+            }
+            toShow.add(ent.icon);
+        }
+
+        ArrayList<View> toRemove = new ArrayList<>();
+        for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
+            View child = mNotificationIcons.getChildAt(i);
+            if (!toShow.contains(child)) {
+                toRemove.add(child);
+            }
+        }
+
+        final int toRemoveCount = toRemove.size();
+        for (int i = 0; i < toRemoveCount; i++) {
+            mNotificationIcons.removeView(toRemove.get(i));
+        }
+
+        for (int i=0; i<toShow.size(); i++) {
+            View v = toShow.get(i);
+            if (v.getParent() == null) {
+                mNotificationIcons.addView(v, i, params);
+            }
+        }
+
+        // Resort notification icons
+        final int childCount = mNotificationIcons.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View actual = mNotificationIcons.getChildAt(i);
+            StatusBarIconView expected = toShow.get(i);
+            if (actual == expected) {
+                continue;
+            }
+            mNotificationIcons.removeView(expected);
+            mNotificationIcons.addView(expected, i);
+        }
+
+        applyNotificationIconsTint();
+    }
+
+    public void hideSystemIconArea(boolean animate) {
+        animateHide(mSystemIconArea, animate);
+    }
+
+    public void showSystemIconArea(boolean animate) {
+        animateShow(mSystemIconArea, animate);
+    }
+
+    public void hideNotificationIconArea(boolean animate) {
+        animateHide(mNotificationIconArea, animate);
+    }
+
+    public void showNotificationIconArea(boolean animate) {
+        animateShow(mNotificationIconArea, animate);
+    }
+
+    public void setClockVisibility(boolean visible) {
+        mClock.setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    public void dump(PrintWriter pw) {
+        int N = mStatusIcons.getChildCount();
+        pw.println("  system icons: " + N);
+        for (int i=0; i<N; i++) {
+            StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
+            pw.println("    [" + i + "] icon=" + ic);
+        }
+    }
+
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (mDemoStatusIcons == null) {
+            mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
+        }
+        mDemoStatusIcons.dispatchDemoCommand(command, args);
+    }
+
+    /**
+     * Hides a view.
+     */
+    private void animateHide(final View v, boolean animate) {
+        v.animate().cancel();
+        if (!animate) {
+            v.setAlpha(0f);
+            v.setVisibility(View.INVISIBLE);
+            return;
+        }
+        v.animate()
+                .alpha(0f)
+                .setDuration(160)
+                .setStartDelay(0)
+                .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        v.setVisibility(View.INVISIBLE);
+                    }
+                });
+    }
+
+    /**
+     * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
+     */
+    private void animateShow(View v, boolean animate) {
+        v.animate().cancel();
+        v.setVisibility(View.VISIBLE);
+        if (!animate) {
+            v.setAlpha(1f);
+            return;
+        }
+        v.animate()
+                .alpha(1f)
+                .setDuration(320)
+                .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                .setStartDelay(50)
+
+                // We need to clean up any pending end action from animateHide if we call
+                // both hide and show in the same frame before the animation actually gets started.
+                // cancel() doesn't really remove the end action.
+                .withEndAction(null);
+
+        // Synchronize the motion with the Keyguard fading if necessary.
+        if (mPhoneStatusBar.isKeyguardFadingAway()) {
+            v.animate()
+                    .setDuration(mPhoneStatusBar.getKeyguardFadingAwayDuration())
+                    .setInterpolator(mLinearOutSlowIn)
+                    .setStartDelay(mPhoneStatusBar.getKeyguardFadingAwayDelay())
+                    .start();
+        }
+    }
+
+    public void setIconTint(int tint) {
+        mIconTint = tint;
+        applyIconTint();
+    }
+
+    private void applyIconTint() {
+        for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
+            StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
+            v.setImageTintList(ColorStateList.valueOf(mIconTint));
+        }
+        mSignalCluster.setIconTint(mIconTint);
+        mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+        mBatteryMeterView.setIconTint(mIconTint);
+        mClock.setTextColor(mIconTint);
+        applyNotificationIconsTint();
+    }
+
+    private void applyNotificationIconsTint() {
+        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
+            StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
+            boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
+            boolean colorize = !isPreL || isGrayscale(v);
+            if (colorize) {
+                v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
+                v.setImageTintList(ColorStateList.valueOf(mIconTint));
+            }
+        }
+    }
+
+    private boolean isGrayscale(StatusBarIconView v) {
+        Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
+        if (isGrayscale != null) {
+            return Boolean.TRUE.equals(isGrayscale);
+        }
+        boolean grayscale = mNotificationColorUtil.isGrayscaleIcon(v.getDrawable());
+        v.setTag(R.id.icon_is_grayscale, grayscale);
+        return grayscale;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index ad4c211..18983ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -17,35 +17,25 @@
 package com.android.systemui.statusbar.policy;
 
 import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.ActionListener;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTracker.WifiListener;
 import com.android.systemui.R;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
-
-// TODO: Unify this logic with platform settings (see WifiSettings and AccessPoint). There is a
-// fair amount of complexity here in statuses and logic beyond just connected/disconnected.
-public class AccessPointControllerImpl implements NetworkController.AccessPointController {
+public class AccessPointControllerImpl
+        implements NetworkController.AccessPointController, WifiListener {
     private static final String TAG = "AccessPointController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -63,25 +53,18 @@
 
     private final Context mContext;
     private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>();
-    private final WifiManager mWifiManager;
+    private final WifiTracker mWifiTracker;
     private final UserManager mUserManager;
-    private final Receiver mReceiver = new Receiver();
 
-    private NetworkControllerImpl mNetworkController;
-    private boolean mScanning;
     private int mCurrentUser;
 
     public AccessPointControllerImpl(Context context) {
         mContext = context;
-        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mWifiTracker = new WifiTracker(context, this, false, true);
         mCurrentUser = ActivityManager.getCurrentUser();
     }
 
-    void setNetworkController(NetworkControllerImpl networkController) {
-        mNetworkController = networkController;
-    }
-
     public boolean canConfigWifi() {
         return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI,
                 new UserHandle(mCurrentUser));
@@ -96,7 +79,9 @@
         if (callback == null || mCallbacks.contains(callback)) return;
         if (DEBUG) Log.d(TAG, "addCallback " + callback);
         mCallbacks.add(callback);
-        mReceiver.setListening(!mCallbacks.isEmpty());
+        if (mCallbacks.size() == 1) {
+            mWifiTracker.startTracking();
+        }
     }
 
     @Override
@@ -104,37 +89,40 @@
         if (callback == null) return;
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
         mCallbacks.remove(callback);
-        mReceiver.setListening(!mCallbacks.isEmpty());
+        if (mCallbacks.isEmpty()) {
+            mWifiTracker.stopTracking();
+        }
     }
 
     @Override
     public void scanForAccessPoints() {
-        if (mScanning) return;
         if (DEBUG) Log.d(TAG, "scan!");
-        mScanning = mWifiManager.startScan();
-        // Grab current networks immediately while we wait for scan.
-        updateAccessPoints();
+        mWifiTracker.forceScan();
+    }
+
+    @Override
+    public int getIcon(AccessPoint ap) {
+        int level = ap.getLevel();
+        return ICONS[level >= 0 ? level : 0];
     }
 
     public boolean connect(AccessPoint ap) {
         if (ap == null) return false;
-        if (DEBUG) Log.d(TAG, "connect networkId=" + ap.networkId);
-        if (ap.networkId < 0) {
+        if (DEBUG) Log.d(TAG, "connect networkId=" + ap.getConfig().networkId);
+        if (ap.isSaved()) {
+            mWifiTracker.getManager().connect(ap.getConfig().networkId, mConnectListener);
+        } else {
             // Unknown network, need to add it.
-            if (ap.hasSecurity) {
+            if (ap.getSecurity() != AccessPoint.SECURITY_NONE) {
                 Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
-                intent.putExtra(EXTRA_START_CONNECT_SSID, ap.ssid);
+                intent.putExtra(EXTRA_START_CONNECT_SSID, ap.getSsid());
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 fireSettingsIntentCallback(intent);
                 return true;
             } else {
-                WifiConfiguration config = new WifiConfiguration();
-                config.SSID = "\"" + ap.ssid + "\"";
-                config.allowedKeyManagement.set(KeyMgmt.NONE);
-                mWifiManager.connect(config, mConnectListener);
+                ap.generateOpenNetworkConfig();
+                mWifiTracker.getManager().connect(ap.getConfig(), mConnectListener);
             }
-        } else {
-            mWifiManager.connect(ap.networkId, mConnectListener);
         }
         return false;
     }
@@ -145,76 +133,28 @@
         }
     }
 
-    private void fireAcccessPointsCallback(AccessPoint[] aps) {
+    private void fireAcccessPointsCallback(List<AccessPoint> aps) {
         for (AccessPointCallback callback : mCallbacks) {
             callback.onAccessPointsChanged(aps);
         }
     }
 
-    private static String trimDoubleQuotes(String v) {
-        return v != null && v.length() >= 2 && v.charAt(0) == '\"'
-                && v.charAt(v.length() - 1) == '\"' ? v.substring(1, v.length() - 1) : v;
+    public void dump(PrintWriter pw) {
+        mWifiTracker.dump(pw);
     }
 
-    private int getConnectedNetworkId(WifiInfo wifiInfo) {
-        return wifiInfo != null ? wifiInfo.getNetworkId() : AccessPoint.NO_NETWORK;
+    @Override
+    public void onWifiStateChanged(int state) {
     }
 
-    private ArrayMap<String, WifiConfiguration> getConfiguredNetworksBySsid() {
-        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
-        if (configs == null || configs.size() == 0) return ArrayMap.EMPTY;
-        final ArrayMap<String, WifiConfiguration> rt = new ArrayMap<String, WifiConfiguration>();
-        for (WifiConfiguration config : configs) {
-            rt.put(trimDoubleQuotes(config.SSID), config);
-        }
-        return rt;
+    @Override
+    public void onConnectedChanged() {
+        fireAcccessPointsCallback(mWifiTracker.getAccessPoints());
     }
 
-    private void updateAccessPoints() {
-        final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-        final int connectedNetworkId = getConnectedNetworkId(wifiInfo);
-        if (DEBUG) Log.d(TAG, "connectedNetworkId: " + connectedNetworkId);
-        final List<ScanResult> scanResults = mWifiManager.getScanResults();
-        final ArrayMap<String, WifiConfiguration> configured = getConfiguredNetworksBySsid();
-        if (DEBUG) Log.d(TAG, "scanResults: " + scanResults);
-        final List<AccessPoint> aps = new ArrayList<AccessPoint>(scanResults.size());
-        final ArraySet<String> ssids = new ArraySet<String>();
-        for (ScanResult scanResult : scanResults) {
-            if (scanResult == null) {
-                continue;
-            }
-            final String ssid = scanResult.SSID;
-            if (TextUtils.isEmpty(ssid) || ssids.contains(ssid)) continue;
-            ssids.add(ssid);
-            final WifiConfiguration config = configured.get(ssid);
-            final int level = WifiManager.calculateSignalLevel(scanResult.level, ICONS.length);
-            final AccessPoint ap = new AccessPoint();
-            ap.isConfigured = config != null;
-            ap.networkId = config != null ? config.networkId : AccessPoint.NO_NETWORK;
-            ap.ssid = ssid;
-            // Connected if either:
-            // -The network ID in the active WifiInfo matches this network's ID.
-            // -The network is ephemeral (no configuration) but the SSID matches.
-            ap.isConnected = (ap.networkId != AccessPoint.NO_NETWORK
-                    && ap.networkId == connectedNetworkId) ||
-                    (ap.networkId == WifiConfiguration.INVALID_NETWORK_ID && wifiInfo != null &&
-                    ap.ssid.equals(trimDoubleQuotes(wifiInfo.getSSID())));
-            if (ap.isConnected && mNetworkController != null) {
-                // Ensure we have the connected network's RSSI.
-                ap.level = mNetworkController.getConnectedWifiLevel();
-            } else {
-                ap.level = level;
-            }
-            ap.iconId = ICONS[ap.level];
-            // Based on Settings AccessPoint#getSecurity, keep up to date
-            // with better methods of determining no security or not.
-            ap.hasSecurity = scanResult.capabilities.contains("WEP")
-                    || scanResult.capabilities.contains("PSK")
-                    || scanResult.capabilities.contains("EAP");
-            aps.add(ap);
-        }
-        Collections.sort(aps, mByStrength);
-        fireAcccessPointsCallback(aps.toArray(new AccessPoint[aps.size()]));
+    @Override
+    public void onAccessPointsChanged() {
+        fireAcccessPointsCallback(mWifiTracker.getAccessPoints());
     }
 
     private final ActionListener mConnectListener = new ActionListener() {
@@ -228,49 +168,4 @@
             if (DEBUG) Log.d(TAG, "connect failure reason=" + reason);
         }
     };
-
-    private final Comparator<AccessPoint> mByStrength = new Comparator<AccessPoint> () {
-        @Override
-        public int compare(AccessPoint lhs, AccessPoint rhs) {
-            return -Integer.compare(score(lhs), score(rhs));
-        }
-
-        private int score(AccessPoint ap) {
-            return ap.level + (ap.isConnected ? 20 : 0) + (ap.isConfigured ? 10 : 0);
-        }
-    };
-
-    private final class Receiver extends BroadcastReceiver {
-        private boolean mRegistered;
-
-        public void setListening(boolean listening) {
-            if (listening && !mRegistered) {
-                if (DEBUG) Log.d(TAG, "Registering receiver");
-                final IntentFilter filter = new IntentFilter();
-                filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-                filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-                filter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
-                filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
-                filter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
-                filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
-                filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-                filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-                mContext.registerReceiver(this, filter);
-                mRegistered = true;
-            } else if (!listening && mRegistered) {
-                if (DEBUG) Log.d(TAG, "Unregistering receiver");
-                mContext.unregisterReceiver(this);
-                mRegistered = false;
-            }
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
-            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
-                updateAccessPoints();
-                mScanning = false;
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 2e3e67a..1566cd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -25,6 +25,9 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -36,6 +39,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
@@ -44,6 +48,8 @@
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback,
@@ -56,6 +62,9 @@
     Rect mTmpRect = new Rect();
     int[] mTmpTwoArray = new int[2];
 
+    private final int mHeadsUpNotificationDecay;
+    private final int mMinimumDisplayTime;
+
     private final int mTouchSensitivityDelay;
     private final float mMaxAlpha = 1f;
     private final ArrayMap<String, Long> mSnoozedPackages;
@@ -66,6 +75,7 @@
 
     private PhoneStatusBar mBar;
 
+    private long mLingerUntilMs;
     private long mStartTouchTime;
     private ViewGroup mContentHolder;
     private int mSnoozeLengthMs;
@@ -74,6 +84,14 @@
     private NotificationData.Entry mHeadsUp;
     private int mUser;
     private String mMostRecentPackageName;
+    private boolean mTouched;
+    private Clock mClock;
+
+    public static class Clock {
+        public long currentTimeMillis() {
+            return SystemClock.elapsedRealtime();
+        }
+    }
 
     public HeadsUpNotificationView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -87,6 +105,24 @@
         mSnoozedPackages = new ArrayMap<>();
         mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
         mSnoozeLengthMs = mDefaultSnoozeLengthMs;
+        mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
+        mHeadsUpNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
+        mClock = new Clock();
+    }
+
+    @VisibleForTesting
+    public HeadsUpNotificationView(Context context, Clock clock, SwipeHelper swipeHelper,
+            EdgeSwipeHelper edgeSwipeHelper, int headsUpNotificationDecay, int minimumDisplayTime,
+            int touchSensitivityDelay, int snoozeLength) {
+        super(context, null);
+        mClock = clock;
+        mSwipeHelper = swipeHelper;
+        mEdgeSwipeHelper = edgeSwipeHelper;
+        mMinimumDisplayTime = minimumDisplayTime;
+        mHeadsUpNotificationDecay = headsUpNotificationDecay;
+        mTouchSensitivityDelay = touchSensitivityDelay;
+        mSnoozedPackages = new ArrayMap<>();
+        mDefaultSnoozeLengthMs = snoozeLength;
     }
 
     public void updateResources() {
@@ -102,90 +138,141 @@
         mBar = bar;
     }
 
+    public PhoneStatusBar getBar() {
+        return mBar;
+    }
+
     public ViewGroup getHolder() {
         return mContentHolder;
     }
 
-    public boolean showNotification(NotificationData.Entry headsUp) {
-        if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) {
+    /**
+     * Called when posting a new notification to the heads up.
+     */
+    public void showNotification(NotificationData.Entry headsUp) {
+        if (DEBUG) Log.v(TAG, "showNotification");
+        if (mHeadsUp != null) {
             // bump any previous heads up back to the shade
-            release();
+            releaseImmediately();
+        }
+        mTouched = false;
+        updateNotification(headsUp, true);
+        mLingerUntilMs = mClock.currentTimeMillis() + mMinimumDisplayTime;
+    }
+
+    /**
+     * Called when updating or posting a notification to the heads up.
+     */
+    public void updateNotification(NotificationData.Entry headsUp, boolean alert) {
+        if (DEBUG) Log.v(TAG, "updateNotification");
+
+        if (alert) {
+            mBar.scheduleHeadsUpDecay(mHeadsUpNotificationDecay);
+        }
+        invalidate();
+
+        if (mHeadsUp == headsUp) {
+            // This is an in-place update.  Noting more to do.
+            return;
         }
 
         mHeadsUp = headsUp;
+
         if (mContentHolder != null) {
             mContentHolder.removeAllViews();
         }
 
         if (mHeadsUp != null) {
             mMostRecentPackageName = mHeadsUp.notification.getPackageName();
-            mHeadsUp.row.setSystemExpanded(true);
-            mHeadsUp.row.setSensitive(false);
-            mHeadsUp.row.setHeadsUp(true);
-            mHeadsUp.row.setHideSensitive(
-                    false, false /* animated */, 0 /* delay */, 0 /* duration */);
-            if (mContentHolder == null) {
-                // too soon!
-                return false;
+            if (mHeadsUp.row != null) {  // only null in tests
+                mHeadsUp.row.setSystemExpanded(true);
+                mHeadsUp.row.setSensitive(false);
+                mHeadsUp.row.setHeadsUp(true);
+                mHeadsUp.row.setHideSensitive(
+                        false, false /* animated */, 0 /* delay */, 0 /* duration */);
             }
-            mContentHolder.setX(0);
-            mContentHolder.setVisibility(View.VISIBLE);
-            mContentHolder.setAlpha(mMaxAlpha);
-            mContentHolder.addView(mHeadsUp.row);
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
 
-            mSwipeHelper.snapChild(mContentHolder, 1f);
             mStartTouchTime = SystemClock.elapsedRealtime() + mTouchSensitivityDelay;
+            if (mContentHolder != null) {  // only null in tests and before we are attached to a window
+                mContentHolder.setX(0);
+                mContentHolder.setVisibility(View.VISIBLE);
+                mContentHolder.setAlpha(mMaxAlpha);
+                mContentHolder.addView(mHeadsUp.row);
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+
+                mSwipeHelper.snapChild(mContentHolder, 1f);
+            }
 
             mHeadsUp.setInterruption();
 
-            // 2. Animate mHeadsUpNotificationView in
+            // Make sure the heads up window is open.
             mBar.scheduleHeadsUpOpen();
-
-            // 3. Set alarm to age the notification off
-            mBar.resetHeadsUpDecayTimer();
         }
-        return true;
+    }
+
+    /**
+     * Possibly enter the lingering state by delaying the closing of the window.
+     *
+     * @return true if the notification has entered the lingering state.
+     */
+    private boolean startLingering(boolean removed) {
+        final long now = mClock.currentTimeMillis();
+        if (!mTouched && mHeadsUp != null && now < mLingerUntilMs) {
+            if (removed) {
+                mHeadsUp = null;
+            }
+            mBar.scheduleHeadsUpDecay(mLingerUntilMs - now);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * React to the removal of the notification in the heads up.
+     */
+    public void removeNotification(String key) {
+        if (DEBUG) Log.v(TAG, "remove");
+        if (mHeadsUp == null || !mHeadsUp.key.equals(key)) {
+            return;
+        }
+        if (!startLingering(/* removed */ true)) {
+            mHeadsUp = null;
+            releaseImmediately();
+        }
+    }
+
+    /**
+     * Ask for any current Heads Up notification to be pushed down into the shade.
+     */
+    public void release() {
+        if (DEBUG) Log.v(TAG, "release");
+        if (!startLingering(/* removed */ false)) {
+            releaseImmediately();
+        }
+    }
+
+    /**
+     * Push any current Heads Up notification down into the shade.
+     */
+    public void releaseImmediately() {
+        if (DEBUG) Log.v(TAG, "releaseImmediately");
+        if (mHeadsUp != null) {
+            mBar.displayNotificationFromHeadsUp(mHeadsUp.notification);
+        }
+        mHeadsUp = null;
+        mBar.scheduleHeadsUpClose();
     }
 
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
+        if (DEBUG) Log.v(TAG, "onVisibilityChanged: " + visibility);
         if (changedView.getVisibility() == VISIBLE) {
+            mStartTouchTime = mClock.currentTimeMillis() + mTouchSensitivityDelay;
             sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         }
     }
 
-    public boolean isShowing(String key) {
-        return mHeadsUp != null && mHeadsUp.key.equals(key);
-    }
-
-    /** Discard the Heads Up notification. */
-    public void clear() {
-        mHeadsUp = null;
-        mBar.scheduleHeadsUpClose();
-    }
-
-    /** Respond to dismissal of the Heads Up window. */
-    public void dismiss() {
-        if (mHeadsUp == null) return;
-        if (mHeadsUp.notification.isClearable()) {
-            mBar.onNotificationClear(mHeadsUp.notification);
-        } else {
-            release();
-        }
-        mHeadsUp = null;
-        mBar.scheduleHeadsUpClose();
-    }
-
-    /** Push any current Heads Up notification down into the shade. */
-    public void release() {
-        if (mHeadsUp != null) {
-            mBar.displayNotificationFromHeadsUp(mHeadsUp.notification);
-        }
-        mHeadsUp = null;
-    }
-
     public boolean isSnoozed(String packageName) {
         final String key = snoozeKey(packageName, mUser);
         Long snoozedUntil = mSnoozedPackages.get(key);
@@ -204,16 +291,15 @@
             mSnoozedPackages.put(snoozeKey(mMostRecentPackageName, mUser),
                     SystemClock.elapsedRealtime() + mSnoozeLengthMs);
         }
-        releaseAndClose();
+        releaseImmediately();
     }
 
     private static String snoozeKey(String packageName, int user) {
         return user + "," + packageName;
     }
 
-    public void releaseAndClose() {
-        release();
-        mBar.scheduleHeadsUpClose();
+    public boolean isShowing(String key) {
+        return mHeadsUp != null && mHeadsUp.key.equals(key);
     }
 
     public NotificationData.Entry getEntry() {
@@ -226,19 +312,19 @@
 
     // ViewGroup methods
 
-    private static final ViewOutlineProvider CONTENT_HOLDER_OUTLINE_PROVIDER =
-            new ViewOutlineProvider() {
-        @Override
-        public void getOutline(View view, Outline outline) {
-            int outlineLeft = view.getPaddingLeft();
-            int outlineTop = view.getPaddingTop();
+private static final ViewOutlineProvider CONTENT_HOLDER_OUTLINE_PROVIDER =
+        new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                int outlineLeft = view.getPaddingLeft();
+                int outlineTop = view.getPaddingTop();
 
-            // Apply padding to shadow.
-            outline.setRect(outlineLeft, outlineTop,
-                    view.getWidth() - outlineLeft - view.getPaddingRight(),
-                    view.getHeight() - outlineTop - view.getPaddingBottom());
-        }
-    };
+                // Apply padding to shadow.
+                outline.setRect(outlineLeft, outlineTop,
+                        view.getWidth() - outlineLeft - view.getPaddingRight(),
+                        view.getHeight() - outlineTop - view.getPaddingBottom());
+            }
+        };
 
     @Override
     public void onAttachedToWindow() {
@@ -246,7 +332,7 @@
         float touchSlop = viewConfiguration.getScaledTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
         mSwipeHelper.setMaxSwipeProgress(mMaxAlpha);
-        mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop);
+        mEdgeSwipeHelper = new EdgeSwipeHelper(this, touchSlop);
 
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
@@ -280,6 +366,7 @@
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
+
     @Override
     protected void onDetachedFromWindow() {
         mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
@@ -288,11 +375,13 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        if (SystemClock.elapsedRealtime() < mStartTouchTime) {
+        if (mClock.currentTimeMillis() < mStartTouchTime) {
             return true;
         }
+        mTouched = true;
         return mEdgeSwipeHelper.onInterceptTouchEvent(ev)
                 || mSwipeHelper.onInterceptTouchEvent(ev)
+                || mHeadsUp == null // lingering
                 || super.onInterceptTouchEvent(ev);
     }
 
@@ -314,12 +403,17 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (SystemClock.elapsedRealtime() < mStartTouchTime) {
+        if (mClock.currentTimeMillis() < mStartTouchTime) {
             return false;
         }
-        mBar.resetHeadsUpDecayTimer();
+
+        final boolean wasRemoved = mHeadsUp == null;
+        if (!wasRemoved) {
+            mBar.scheduleHeadsUpDecay(mHeadsUpNotificationDecay);
+        }
         return mEdgeSwipeHelper.onTouchEvent(ev)
                 || mSwipeHelper.onTouchEvent(ev)
+                || wasRemoved
                 || super.onTouchEvent(ev);
     }
 
@@ -388,7 +482,11 @@
     @Override
     public void onChildDismissed(View v) {
         Log.v(TAG, "User swiped heads up to dismiss");
-        mBar.onHeadsUpDismissed();
+        if (mHeadsUp != null && mHeadsUp.notification.isClearable()) {
+            mBar.onNotificationClear(mHeadsUp.notification);
+            mHeadsUp = null;
+        }
+        releaseImmediately();
     }
 
     @Override
@@ -442,14 +540,39 @@
         mUser = user;
     }
 
-    private class EdgeSwipeHelper implements Gefingerpoken {
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("HeadsUpNotificationView state:");
+        pw.print("  mTouchSensitivityDelay="); pw.println(mTouchSensitivityDelay);
+        pw.print("  mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
+        pw.print("  mLingerUntilMs="); pw.println(mLingerUntilMs);
+        pw.print("  mTouched="); pw.println(mTouched);
+        pw.print("  mMostRecentPackageName="); pw.println(mMostRecentPackageName);
+        pw.print("  mStartTouchTime="); pw.println(mStartTouchTime);
+        pw.print("  now="); pw.println(SystemClock.elapsedRealtime());
+        pw.print("  mUser="); pw.println(mUser);
+        if (mHeadsUp == null) {
+            pw.println("  mHeadsUp=null");
+        } else {
+            pw.print("  mHeadsUp="); pw.println(mHeadsUp.notification.getKey());
+        }
+        int N = mSnoozedPackages.size();
+        pw.println("  snoozed packages: " + N);
+        for (int i = 0; i < N; i++) {
+            pw.print("    "); pw.print(mSnoozedPackages.valueAt(i));
+            pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));
+        }
+    }
+
+    public static class EdgeSwipeHelper implements Gefingerpoken {
         private static final boolean DEBUG_EDGE_SWIPE = false;
         private final float mTouchSlop;
+        private final HeadsUpNotificationView mHeadsUpView;
         private boolean mConsuming;
         private float mFirstY;
         private float mFirstX;
 
-        public EdgeSwipeHelper(float touchSlop) {
+        public EdgeSwipeHelper(HeadsUpNotificationView headsUpView, float touchSlop) {
+            mHeadsUpView = headsUpView;
             mTouchSlop = touchSlop;
         }
 
@@ -469,10 +592,10 @@
                     final float daX = Math.abs(ev.getX() - mFirstX);
                     final float daY = Math.abs(dY);
                     if (!mConsuming && daX < daY && daY > mTouchSlop) {
-                        snooze();
+                        mHeadsUpView.snooze();
                         if (dY > 0) {
                             if (DEBUG_EDGE_SWIPE) Log.d(TAG, "found an open");
-                            mBar.animateExpandNotificationsPanel();
+                            mHeadsUpView.getBar().animateExpandNotificationsPanel();
                         }
                         mConsuming = true;
                     }
@@ -480,7 +603,7 @@
 
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
-                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action done" );
+                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action done");
                     mConsuming = false;
                     break;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index af92423..ba938cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -28,7 +28,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.systemui.R;
@@ -57,7 +56,6 @@
     // Since some pieces of the phone state are interdependent we store it locally,
     // this could potentially become part of MobileState for simplification/complication
     // of code.
-    private IccCardConstants.State mSimState = IccCardConstants.State.READY;
     private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
     private ServiceState mServiceState;
@@ -98,59 +96,10 @@
         updateTelephony();
     }
 
-    /**
-     * Get (the mobile parts of) the carrier string.
-     *
-     * @param currentLabel can be used for concatenation, currently just empty
-     * @param connected whether the device has connection to the internet at all
-     * @param isMobileLabel whether to always return the network or just when data is connected
-     */
-    public String getLabel(String currentLabel, boolean connected, boolean isMobileLabel) {
-        if (!mCurrentState.enabled) {
-            return "";
-        } else {
-            String mobileLabel = "";
-            // We want to show the carrier name if in service and either:
-            // - We are connected to mobile data, or
-            // - We are not connected to mobile data, as long as the *reason* packets are not
-            //   being routed over that link is that we have better connectivity via wifi.
-            // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
-            // is connected, we show nothing.
-            // Otherwise (nothing connected) we show "No internet connection".
-            if (mCurrentState.dataConnected) {
-                mobileLabel = mCurrentState.networkName;
-            } else if (connected || mCurrentState.isEmergency) {
-                if (mCurrentState.connected || mCurrentState.isEmergency) {
-                    // The isEmergencyOnly test covers the case of a phone with no SIM
-                    mobileLabel = mCurrentState.networkName;
-                }
-            } else {
-                mobileLabel = mContext.getString(
-                        R.string.status_bar_settings_signal_meter_disconnected);
-            }
-
-            if (currentLabel.length() != 0) {
-                currentLabel = currentLabel + mNetworkNameSeparator;
-            }
-            // Now for things that should only be shown when actually using mobile data.
-            if (isMobileLabel) {
-                return currentLabel + mobileLabel;
-            } else {
-                return currentLabel
-                        + (mCurrentState.dataConnected ? mobileLabel : currentLabel);
-            }
-        }
-    }
-
     public int getDataContentDescription() {
         return getIcons().mDataContentDescription;
     }
 
-    @VisibleForTesting
-    protected IccCardConstants.State getSimState() {
-        return mSimState;
-    }
-
     public void setAirplaneMode(boolean airplaneMode) {
         mCurrentState.airplaneMode = airplaneMode;
         notifyListenersIfNecessary();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 3cffc85..9212837 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -18,6 +18,10 @@
 
 import android.content.Intent;
 
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.util.List;
+
 public interface NetworkController {
 
     boolean hasMobileDataFeature();
@@ -50,25 +54,14 @@
         void addAccessPointCallback(AccessPointCallback callback);
         void removeAccessPointCallback(AccessPointCallback callback);
         void scanForAccessPoints();
+        int getIcon(AccessPoint ap);
         boolean connect(AccessPoint ap);
         boolean canConfigWifi();
 
         public interface AccessPointCallback {
-            void onAccessPointsChanged(AccessPoint[] accessPoints);
+            void onAccessPointsChanged(List<AccessPoint> accessPoints);
             void onSettingsActivityTriggered(Intent settingsIntent);
         }
-
-        public static class AccessPoint {
-            public static final int NO_NETWORK = -1;  // see WifiManager
-
-            public int networkId;
-            public int iconId;
-            public String ssid;
-            public boolean isConnected;
-            public boolean isConfigured;
-            public boolean hasSecurity;
-            public int level;  // 0 - 5
-        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 1d37ee3..bb3eb7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -17,8 +17,6 @@
 package com.android.systemui.statusbar.policy;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -84,12 +82,6 @@
     private final AccessPointControllerImpl mAccessPoints;
     private final MobileDataControllerImpl mMobileDataController;
 
-    // Network types that replace the carrier label if the device does not support mobile data.
-    private boolean mBluetoothTethered = false;
-    private boolean mEthernetConnected = false;
-
-    // state of inet connection
-    private boolean mConnected = false;
     private boolean mInetCondition; // Used for Logging and demo.
 
     // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are
@@ -107,8 +99,6 @@
 
     // All the callbacks.
     private ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<EmergencyListener>();
-    private ArrayList<CarrierLabelListener> mCarrierListeners =
-            new ArrayList<CarrierLabelListener>();
     private ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
     private ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
             new ArrayList<NetworkSignalChangedCallback>();
@@ -166,7 +156,6 @@
 
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode(true /* force callback */);
-        mAccessPoints.setNetworkController(this);
     }
 
     private void registerListeners() {
@@ -222,11 +211,6 @@
         listener.setEmergencyCallsOnly(isEmergencyOnly());
     }
 
-    public void addCarrierLabel(CarrierLabelListener listener) {
-        mCarrierListeners.add(listener);
-        refreshCarrierLabel();
-    }
-
     private void notifyMobileDataEnabled(boolean enabled) {
         final int length = mSignalsChangedCallbacks.size();
         for (int i = 0; i < length; i++) {
@@ -288,9 +272,6 @@
         for (int i = 0; i < length; i++) {
             mEmergencyListeners.get(i).setEmergencyCallsOnly(emergencyOnly);
         }
-        // If the emergency has a chance to change, then so does the carrier
-        // label.
-        refreshCarrierLabel();
     }
 
     public void addSignalCluster(SignalCluster cluster) {
@@ -342,7 +323,6 @@
         mCurrentUserId = newUserId;
         mAccessPoints.onUserSwitched(newUserId);
         updateConnectivity();
-        refreshCarrierLabel();
     }
 
     @Override
@@ -354,14 +334,12 @@
         if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) ||
                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
             updateConnectivity();
-            refreshCarrierLabel();
         } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
             mConfig = Config.readConfig(mContext);
             handleConfigurationChanged();
         } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
             refreshLocale();
             updateAirplaneMode(false);
-            refreshCarrierLabel();
         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) {
             // We are using different subs now, we might be able to make calls.
             recalculateEmergency();
@@ -397,7 +375,6 @@
             mobileSignalController.setConfiguration(mConfig);
         }
         refreshLocale();
-        refreshCarrierLabel();
     }
 
     private void updateMobileControllers() {
@@ -503,7 +480,6 @@
                 mobileSignalController.setAirplaneMode(mAirplaneMode);
             }
             notifyListeners();
-            refreshCarrierLabel();
         }
     }
 
@@ -567,10 +543,7 @@
             Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
         }
 
-        mConnected = !mConnectedTransports.isEmpty();
         mInetCondition = !mValidatedTransports.isEmpty();
-        mBluetoothTethered = mConnectedTransports.get(TRANSPORT_BLUETOOTH);
-        mEthernetConnected = mConnectedTransports.get(TRANSPORT_ETHERNET);
 
         pushConnectivityToSignals();
     }
@@ -589,59 +562,6 @@
                 mValidatedTransports.get(mWifiSignalController.getTransportType()) ? 1 : 0);
     }
 
-    /**
-     * Recalculate and update the carrier label.
-     */
-    void refreshCarrierLabel() {
-        Context context = mContext;
-
-        WifiSignalController.WifiState wifiState = mWifiSignalController.getState();
-        String label = "";
-        for (MobileSignalController controller : mMobileSignalControllers.values()) {
-            label = controller.getLabel(label, mConnected, mHasMobileDataFeature);
-        }
-
-        // TODO Simplify this ugliness, some of the flows below shouldn't be possible anymore
-        // but stay for the sake of history.
-        if (mBluetoothTethered && !mHasMobileDataFeature) {
-            label = mContext.getString(R.string.bluetooth_tethered);
-        }
-
-        if (mEthernetConnected && !mHasMobileDataFeature) {
-            label = context.getString(R.string.ethernet_label);
-        }
-
-        if (mAirplaneMode && !isEmergencyOnly()) {
-            // combined values from connected wifi take precedence over airplane mode
-            if (wifiState.connected && mHasMobileDataFeature) {
-                // Suppress "No internet connection." from mobile if wifi connected.
-                label = "";
-            } else {
-                 if (!mHasMobileDataFeature) {
-                      label = context.getString(
-                              R.string.status_bar_settings_signal_meter_disconnected);
-                 }
-            }
-        } else if (!isMobileDataConnected() && !wifiState.connected && !mBluetoothTethered &&
-                 !mEthernetConnected && !mHasMobileDataFeature) {
-            // Pretty much no connection.
-            label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-        }
-
-        // for mobile devices, we always show mobile connection info here (SPN/PLMN)
-        // for other devices, we show whatever network is connected
-        // This is determined above by references to mHasMobileDataFeature.
-        int length = mCarrierListeners.size();
-        for (int i = 0; i < length; i++) {
-            mCarrierListeners.get(i).setCarrierLabel(label);
-        }
-    }
-
-    private boolean isMobileDataConnected() {
-        MobileSignalController controller = getDataController();
-        return controller != null ? controller.getState().dataConnected : false;
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NetworkController state:");
 
@@ -649,10 +569,6 @@
         pw.print("  hasVoiceCallingFeature()=");
         pw.println(hasVoiceCallingFeature());
 
-        pw.println("  - Bluetooth ----");
-        pw.print("  mBtReverseTethered=");
-        pw.println(mBluetoothTethered);
-
         pw.println("  - connectivity ------");
         pw.print("  mConnectedTransports=");
         pw.println(mConnectedTransports);
@@ -669,6 +585,8 @@
             mobileSignalController.dump(pw);
         }
         mWifiSignalController.dump(pw);
+
+        mAccessPoints.dump(pw);
     }
 
     private boolean mDemoMode;
@@ -695,7 +613,6 @@
             mWifiSignalController.resetLastState();
             registerListeners();
             notifyAllListeners();
-            refreshCarrierLabel();
         } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
             String airplane = args.getString("airplane");
             if (airplane != null) {
@@ -787,7 +704,6 @@
                 controller.getState().enabled = show;
                 controller.notifyListeners();
             }
-            refreshCarrierLabel();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index 14c3d9c..8379b93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -167,7 +167,6 @@
         if (isDirty()) {
             saveLastState();
             notifyListeners();
-            mNetworkController.refreshCarrierLabel();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 600b750..0e21457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -31,6 +31,7 @@
     void setUserId(int userId);
     boolean isZenAvailable();
     ComponentName getEffectsSuppressor();
+    boolean isCountdownConditionSupported();
 
     public static class Callback {
         public void onZenChanged(int zen) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 37ed7d8..dbdb578 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -169,6 +169,12 @@
         return NotificationManager.from(mContext).getEffectsSuppressor();
     }
 
+    @Override
+    public boolean isCountdownConditionSupported() {
+        return NotificationManager.from(mContext)
+                .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
+    }
+
     private void fireNextAlarmChanged() {
         for (Callback cb : mCallbacks) {
             cb.onNextAlarmChanged();
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 0a14cf5..6f2a392 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -127,7 +127,7 @@
     }
 
     @Override
-    public void resetHeadsUpDecayTimer() {
+    public void scheduleHeadsUpDecay(long delay) {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index acdcfc1..31264ee 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -37,7 +37,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
-import android.media.AudioService;
 import android.media.AudioSystem;
 import android.media.RingtoneManager;
 import android.media.ToneGenerator;
@@ -88,7 +87,7 @@
     private static final String TAG = "VolumePanel";
     private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
+    private static final int PLAY_SOUND_DELAY = AudioSystem.PLAY_SOUND_DELAY;
 
     /**
      * The delay before vibrating. This small period exists so if the user is
@@ -351,6 +350,17 @@
         };
     }
 
+    protected LayoutParams getDialogLayoutParams(Window window, Resources res) {
+        final LayoutParams lp = window.getAttributes();
+        lp.token = null;
+        lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+        lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+        lp.setTitle(TAG);
+        return lp;
+    }
+
     public VolumePanel(Context context, ZenModeController zenController) {
         mTag = String.format("%s.%08x", TAG, hashCode());
         mContext = context;
@@ -409,14 +419,7 @@
 
         mDialog.create();
 
-        final LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.format = PixelFormat.TRANSLUCENT;
-        lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
-        lp.setTitle(TAG);
-        window.setAttributes(lp);
+        window.setAttributes(getDialogLayoutParams(window, res));
 
         updateWidth();
 
@@ -602,7 +605,7 @@
 
     private int getStreamVolume(int streamType) {
         if (streamType == STREAM_MASTER) {
-            return mAudioManager.getMasterVolume();
+            return mAudioManager.getLastAudibleMasterVolume();
         } else if (streamType == STREAM_REMOTE_MUSIC) {
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
@@ -613,7 +616,7 @@
             }
             return -1;
         } else {
-            return mAudioManager.getStreamVolume(streamType);
+            return mAudioManager.getLastAudibleStreamVolume(streamType);
         }
     }
 
@@ -1012,7 +1015,7 @@
     }
 
     private static String streamToString(int stream) {
-        return AudioService.streamToString(stream);
+        return AudioSystem.streamToString(stream);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index d40a2c0..5726fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -19,7 +19,6 @@
 import android.animation.LayoutTransition;
 import android.animation.LayoutTransition.TransitionListener;
 import android.app.ActivityManager;
-import android.app.NotificationManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -85,10 +84,6 @@
     private final int mSubheadWarningColor;
     private final int mSubheadColor;
     private final Interpolator mInterpolator;
-    private final int mMaxConditions;
-    private final int mMaxOptionalConditions;
-    private final boolean mCountdownConditionSupported;
-    private final int mFirstConditionIndex;
     private final TransitionHelper mTransitionHelper = new TransitionHelper();
     private final Uri mForeverId;
 
@@ -103,6 +98,10 @@
 
     private Callback mCallback;
     private ZenModeController mController;
+    private boolean mCountdownConditionSupported;
+    private int mMaxConditions;
+    private int mMaxOptionalConditions;
+    private int mFirstConditionIndex;
     private boolean mRequestingConditions;
     private Condition mExitCondition;
     private String mExitConditionText;
@@ -127,14 +126,6 @@
         mSubheadColor = res.getColor(R.color.qs_subhead);
         mInterpolator = AnimationUtils.loadInterpolator(mContext,
                 com.android.internal.R.interpolator.fast_out_slow_in);
-        mCountdownConditionSupported = NotificationManager.from(mContext)
-                .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
-        final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
-        mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
-        final int minConditions = 1 /*forever*/ + countdownDelta;
-        mMaxConditions = MathUtils.constrain(res.getInteger(R.integer.zen_mode_max_conditions),
-                minConditions, 100);
-        mMaxOptionalConditions = mMaxConditions - minConditions;
         mForeverId = Condition.newId(mContext).appendPath("forever").build();
         if (DEBUG) Log.d(mTag, "new ZenModePanel");
     }
@@ -192,9 +183,6 @@
         Interaction.register(mMoreSettings, mInteractionCallback);
 
         mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
-        for (int i = 0; i < mMaxConditions; i++) {
-            mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
-        }
 
         setLayoutTransition(newLayoutTransition(mTransitionHelper));
     }
@@ -306,6 +294,16 @@
 
     public void init(ZenModeController controller) {
         mController = controller;
+        mCountdownConditionSupported = mController.isCountdownConditionSupported();
+        final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
+        mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
+        final int minConditions = 1 /*forever*/ + countdownDelta;
+        mMaxConditions = MathUtils.constrain(mContext.getResources()
+                .getInteger(R.integer.zen_mode_max_conditions), minConditions, 100);
+        mMaxOptionalConditions = mMaxConditions - minConditions;
+        for (int i = 0; i < mMaxConditions; i++) {
+            mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
+        }
         setExitCondition(mController.getExitCondition());
         refreshExitConditionText();
         mSessionZen = getSelectedZen(-1);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 5a90324..6a7201c 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -36,4 +36,6 @@
 # UI it doesn't own. This is necessary to allow screenshots to be taken
 LOCAL_CERTIFICATE := platform
 
+include frameworks/base/packages/SettingsLib/common.mk
+
 include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
new file mode 100644
index 0000000..3fdb3d2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui;
+
+import android.test.AndroidTestCase;
+
+/**
+ * Base class that does System UI specific setup.
+ */
+public class SysuiTestCase extends AndroidTestCase {
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Mockito stuff.
+        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java
new file mode 100644
index 0000000..e8a80d9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.*;
+import android.service.notification.StatusBarNotification;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test the Heads Up Notification.
+ *
+ * Specifically the policy that a notificaiton must remain visibile for a minimum period of time.
+ */
+public class HeadsUpNotificationTest extends SysuiTestCase {
+    private static final String TAG = "HeadsUpNotificationTest";
+
+    private static int TOUCH_SENSITIVITY = 100;
+    private static int NOTIFICATION_DECAY = 10000;
+    private static int MINIMUM_DISPLAY_TIME = 3000;
+    private static int SNOOZE_TIME = 60000;
+    private static long TOO_SOON = 1000L;  // less than MINIMUM_DISPLAY_TIME
+    private static long LATER = 5000L;  // more than MINIMUM_DISPLAY_TIME
+    private static long REMAINING_VISIBILITY = MINIMUM_DISPLAY_TIME - TOO_SOON;
+
+    protected HeadsUpNotificationView mHeadsUp;
+
+    @Mock protected PhoneStatusBar mMockStatusBar;
+    @Mock private HeadsUpNotificationView.Clock mClock;
+    @Mock private SwipeHelper mMockSwipeHelper;
+    @Mock private HeadsUpNotificationView.EdgeSwipeHelper mMockEdgeSwipeHelper;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        MockitoAnnotations.initMocks(this);
+
+        mHeadsUp = new HeadsUpNotificationView(mContext,
+                mClock, mMockSwipeHelper, mMockEdgeSwipeHelper,
+                NOTIFICATION_DECAY, MINIMUM_DISPLAY_TIME, TOUCH_SENSITIVITY, SNOOZE_TIME);
+        mHeadsUp.setBar(mMockStatusBar);
+    }
+
+    private NotificationData.Entry makeNotification(String key) {
+        StatusBarNotification sbn = mock(StatusBarNotification.class);
+        when(sbn.getKey()).thenReturn(key);
+        return new NotificationData.Entry(sbn, null);
+    }
+
+    public void testPostAndDecay() {
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpOpen();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar).scheduleHeadsUpDecay(decayArg.capture());
+        // New notification gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndDeleteTooSoon() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.removeNotification(a.key);
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar).scheduleHeadsUpDecay(decayArg.capture());
+        // Leave the window up for the balance of the minumum time.
+        assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndDeleteLater() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(LATER);
+        mHeadsUp.removeNotification(a.key);
+        // Delete closes immediately if the minimum time window is satisfied.
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    // This is a bad test.  It should not care that there is a call to scheduleHeadsUpClose(),
+    // but it happens that there will be one, so it is important that it happen before the
+    // call to scheduleHeadsUpOpen(), so that the final state is open.
+    // Maybe mMockStatusBar should instead be a fake that tracks the open/closed state.
+    public void testPostAndReplaceTooSoon() {
+        InOrder callOrder = inOrder(mMockStatusBar);
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry b = makeNotification("b");
+        mHeadsUp.showNotification(b);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // New notification gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+
+        // Make sure close was called before open, so that the heads up stays open.
+        callOrder.verify(mMockStatusBar).scheduleHeadsUpClose();
+        callOrder.verify(mMockStatusBar).scheduleHeadsUpOpen();
+    }
+
+    public void testPostAndUpdateAlertAgain() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.updateNotification(a, true);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Alert again gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateAlertAgainFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, true);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Alert again gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateNoAlertAgain() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.updateNotification(a, false);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    public void testPostAndUpdateNoAlertAgainFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, false);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    public void testPostAndUpdateLowPriorityTooSoon() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.release();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Down grade on update leaves the window up for the balance of the minumum time.
+        assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateLowPriorityTooSoonFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, false);
+        mHeadsUp.release();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Down grade on update leaves the window up for the balance of the minumum time.
+        assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateLowPriorityLater() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(LATER);
+        mHeadsUp.release();
+        // Down grade on update closes immediately if the minimum time window is satisfied.
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    public void testPostAndUpdateLowPriorityLaterFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(LATER);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, false);
+        mHeadsUp.release();
+        // Down grade on update closes immediately if the minimum time window is satisfied.
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 9b95d5c..5d88407 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -29,11 +29,11 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.cdma.EriInfo;
+import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
@@ -46,7 +46,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class NetworkControllerBaseTest extends AndroidTestCase {
+public class NetworkControllerBaseTest extends SysuiTestCase {
     private static final String TAG = "NetworkControllerBaseTest";
     protected static final int DEFAULT_LEVEL = 2;
     protected static final int DEFAULT_SIGNAL_STRENGTH =
@@ -69,14 +69,13 @@
     protected TelephonyManager mMockTm;
     protected Config mConfig;
 
+    protected int mSubId;
+
     private NetworkCapabilities mNetCapabilities;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        // Mockito stuff.
-        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
-        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
         mMockWm = mock(WifiManager.class);
         mMockTm = mock(TelephonyManager.class);
@@ -100,13 +99,13 @@
 
     protected void setupNetworkController() {
         // For now just pretend to be the data sim, so we can test that too.
-        final int subId = SubscriptionManager.getDefaultDataSubId();
+        mSubId = SubscriptionManager.getDefaultDataSubId();
         SubscriptionInfo subscription = mock(SubscriptionInfo.class);
         List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>();
-        when(subscription.getSubscriptionId()).thenReturn(subId);
+        when(subscription.getSubscriptionId()).thenReturn(mSubId);
         subs.add(subscription);
         mNetworkController.setCurrentSubscriptions(subs);
-        mMobileSignalController = mNetworkController.mMobileSignalControllers.get(subId);
+        mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
         mPhoneStateListener = mMobileSignalController.mPhoneStateListener;
         mSignalCluster = mock(SignalCluster.class);
         mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
@@ -291,10 +290,6 @@
         assertEquals("Visibility in status bar", visible, (boolean) visibleArg.getValue());
     }
 
-   protected void assertSimStateEquals(IccCardConstants.State expected) {
-       assertEquals("Sim state", expected, mMobileSignalController.getSimState());
-   }
-
    protected void assertNetworkNameEquals(String expected) {
        assertEquals("Network name", expected, mNetworkController.getMobileNetworkName());
    }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 65b0971..7fa3f68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -25,6 +25,7 @@
 import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
 
@@ -254,16 +255,6 @@
         setCdmaRoaming(false);
     }
 
-    public void testOnReceive_updateSimState_noSim() {
-        Intent intent = new Intent();
-        intent.setAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
-
-        mNetworkController.onReceive(mContext, intent);
-
-        assertSimStateEquals(IccCardConstants.State.ABSENT);
-    }
-
     public void testOnReceive_stringsUpdatedAction_spn() {
         String expectedMNetworkName = "Test";
         Intent intent = createStringsUpdatedIntent(true /* showSpn */,
@@ -344,6 +335,7 @@
 
         intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
         intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId);
 
         return intent;
     }
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index c6b76f1..74391eb 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -72,16 +72,22 @@
         @Override
         public String resolvePacFile(String host, String url) throws RemoteException {
             try {
+                if (host == null) {
+                    throw new IllegalArgumentException("The host must not be null");
+                }
+                if (url == null) {
+                    throw new IllegalArgumentException("The URL must not be null");
+                }
                 // Check for characters that could be used for an injection attack.
                 new URL(url);
                 for (char c : host.toCharArray()) {
                     if (!Character.isLetterOrDigit(c) && (c != '.') && (c != '-')) {
-                        throw new RemoteException("Invalid host was passed");
+                        throw new IllegalArgumentException("Invalid host was passed");
                     }
                 }
                 return mPacNative.makeProxyRequest(url, host);
             } catch (MalformedURLException e) {
-                throw new RemoteException("Invalid URL was passed");
+                throw new IllegalArgumentException("Invalid URL was passed");
             }
         }
 
diff --git a/policy/Android.mk b/policy/Android.mk
deleted file mode 100644
index 47d8fb8..0000000
--- a/policy/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-            
-LOCAL_MODULE := android.policy
-
-include $(BUILD_JAVA_LIBRARY)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java
deleted file mode 100644
index 42bfc5f..0000000
--- a/policy/src/com/android/internal/policy/impl/Policy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.policy.IPolicy;
-
-/**
- * {@hide}
- */
-
-// Simple implementation of the policy interface that spawns the right
-// set of objects
-public class Policy implements IPolicy {
-    private static final String TAG = "PhonePolicy";
-
-    private static final String[] preload_classes = {
-        "com.android.internal.policy.impl.PhoneLayoutInflater",
-        "com.android.internal.policy.impl.PhoneWindow",
-        "com.android.internal.policy.impl.PhoneWindow$1",
-        "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
-        "com.android.internal.policy.impl.PhoneWindow$DecorView",
-        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
-        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
-    };
-
-    static {
-        // For performance reasons, preload some policy specific classes when
-        // the policy gets loaded.
-        for (String s : preload_classes) {
-            try {
-                Class.forName(s);
-            } catch (ClassNotFoundException ex) {
-                Log.e(TAG, "Could not preload class for phone policy: " + s);
-            }
-        }
-    }
-
-    public Window makeNewWindow(Context context) {
-        return new PhoneWindow(context);
-    }
-
-    public LayoutInflater makeNewLayoutInflater(Context context) {
-        return new PhoneLayoutInflater(context);
-    }
-
-    public WindowManagerPolicy makeNewWindowManager() {
-        return new PhoneWindowManager();
-    }
-
-    public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
-        return new PhoneFallbackEventHandler(context);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/ShortcutManager.java b/policy/src/com/android/internal/policy/impl/ShortcutManager.java
deleted file mode 100644
index bb898f7..0000000
--- a/policy/src/com/android/internal/policy/impl/ShortcutManager.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyCharacterMap;
-
-import java.net.URISyntaxException;
-
-/**
- * Manages quick launch shortcuts by:
- * <li> Keeping the local copy in sync with the database (this is an observer)
- * <li> Returning a shortcut-matching intent to clients
- */
-class ShortcutManager extends ContentObserver {
-    
-    private static final String TAG = "ShortcutManager";
-    
-    private static final int COLUMN_SHORTCUT = 0;
-    private static final int COLUMN_INTENT = 1;
-    private static final String[] sProjection = new String[] {
-        Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
-    };
-
-    private Context mContext;
-    private Cursor mCursor;
-    /** Map of a shortcut to its intent. */
-    private SparseArray<Intent> mShortcutIntents;
-    
-    public ShortcutManager(Context context, Handler handler) {
-        super(handler);
-        
-        mContext = context;
-        mShortcutIntents = new SparseArray<Intent>();
-    }
-
-    /** Observes the provider of shortcut+intents */
-    public void observe() {
-        mCursor = mContext.getContentResolver().query(
-                Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
-        mCursor.registerContentObserver(this);
-        updateShortcuts();
-    }
-
-    @Override
-    public void onChange(boolean selfChange) {
-        updateShortcuts();
-    }
-    
-    private void updateShortcuts() {
-        Cursor c = mCursor;
-        if (!c.requery()) {
-            Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
-            return;
-        }
-
-        mShortcutIntents.clear();
-        while (c.moveToNext()) {
-            int shortcut = c.getInt(COLUMN_SHORTCUT);
-            if (shortcut == 0) continue;
-            String intentURI = c.getString(COLUMN_INTENT);
-            Intent intent = null;
-            try {
-                intent = Intent.getIntent(intentURI);
-            } catch (URISyntaxException e) {
-                Log.w(TAG, "Intent URI for shortcut invalid.", e);
-            }
-            if (intent == null) continue;
-            mShortcutIntents.put(shortcut, intent);
-        }
-    }
-    
-    /**
-     * Gets the shortcut intent for a given keycode+modifier. Make sure you
-     * strip whatever modifier is used for invoking shortcuts (for example,
-     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
-     * 'Sym' bit from the modifiers before calling this method.
-     * <p>
-     * This will first try an exact match (with modifiers), and then try a
-     * match without modifiers (primary character on a key).
-     * 
-     * @param kcm The key character map of the device on which the key was pressed.
-     * @param keyCode The key code.
-     * @param metaState The meta state, omitting any modifiers that were used
-     * to invoke the shortcut.
-     * @return The intent that matches the shortcut, or null if not found.
-     */
-    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
-        Intent intent = null;
-
-        // First try the exact keycode (with modifiers).
-        int shortcut = kcm.get(keyCode, metaState);
-        if (shortcut != 0) {
-            intent = mShortcutIntents.get(shortcut);
-        }
-
-        // Next try the primary character on that key.
-        if (intent == null) {
-            shortcut = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
-            if (shortcut != 0) {
-                intent = mShortcutIntents.get(shortcut);
-            }
-        }
-
-        return intent;
-    }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/package.html b/policy/src/com/android/internal/policy/impl/package.html
deleted file mode 100644
index c9f96a6..0000000
--- a/policy/src/com/android/internal/policy/impl/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 4e89566..4af6688 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -58,15 +58,13 @@
     Allocation mAdaptedAllocation;
     int mSize;
 
-    boolean mConstrainedLOD;
-    boolean mConstrainedFace;
-    boolean mConstrainedY;
-    boolean mConstrainedZ;
     boolean mReadAllowed = true;
     boolean mWriteAllowed = true;
+    int mSelectedX;
     int mSelectedY;
     int mSelectedZ;
     int mSelectedLOD;
+    int mSelectedArray[];
     Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
 
     int mCurrentDimX;
@@ -1882,4 +1880,15 @@
         }
     }
 
+    /**
+     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
+     *
+     */
+    @Override
+    public void destroy() {
+        if((mUsage & USAGE_IO_OUTPUT) != 0) {
+            setSurface(null);
+        }
+        super.destroy();
+    }
 }
diff --git a/rs/java/android/renderscript/AllocationAdapter.java b/rs/java/android/renderscript/AllocationAdapter.java
index 3522a52..9e28f7c 100644
--- a/rs/java/android/renderscript/AllocationAdapter.java
+++ b/rs/java/android/renderscript/AllocationAdapter.java
@@ -21,76 +21,20 @@
  *
  **/
 public class AllocationAdapter extends Allocation {
-    AllocationAdapter(long id, RenderScript rs, Allocation alloc) {
+    Type mWindow;
+
+    AllocationAdapter(long id, RenderScript rs, Allocation alloc, Type t) {
         super(id, rs, alloc.mType, alloc.mUsage);
         mAdaptedAllocation = alloc;
+        mWindow = t;
     }
 
+    /*
     long getID(RenderScript rs) {
         throw new RSInvalidStateException(
             "This operation is not supported with adapters at this time.");
     }
-
-    /**
-     * @hide
-     */
-    public void subData(int xoff, FieldPacker fp) {
-        super.setFromFieldPacker(xoff, fp);
-    }
-    /**
-     * @hide
-     */
-    public void subElementData(int xoff, int component_number, FieldPacker fp) {
-        super.setFromFieldPacker(xoff, component_number, fp);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, int[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, short[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, byte[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, float[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
-        super.copy2DRangeFrom(xoff, yoff, w, h, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
-        super.copy2DRangeFrom(xoff, yoff, w, h, d);
-    }
-    /**
-     * @hide
-     */
-    public void readData(int[] d) {
-        super.copyTo(d);
-    }
-    /**
-     * @hide
-     */
-    public void readData(float[] d) {
-        super.copyTo(d);
-    }
+    */
 
     void initLOD(int lod) {
         if (lod < 0) {
@@ -125,6 +69,26 @@
         mSelectedZ = 0;
     }
 
+    private void updateOffsets() {
+        int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
+
+        if (mSelectedArray.length > 0) {
+            a1 = mSelectedArray[0];
+        }
+        if (mSelectedArray.length > 1) {
+            a2 = mSelectedArray[2];
+        }
+        if (mSelectedArray.length > 2) {
+            a3 = mSelectedArray[2];
+        }
+        if (mSelectedArray.length > 3) {
+            a4 = mSelectedArray[3];
+        }
+        mRS.nAllocationAdapterOffset(getID(mRS), mSelectedX, mSelectedY, mSelectedZ,
+                                     mSelectedLOD, mSelectedFace.mID, a1, a2, a3, a4);
+
+    }
+
     /**
      * Set the active LOD.  The LOD must be within the range for the
      * type being adapted.  The base allocation must have mipmaps.
@@ -138,11 +102,13 @@
         if (!mAdaptedAllocation.getType().hasMipmaps()) {
             throw new RSInvalidStateException("Cannot set LOD when the allocation type does not include mipmaps.");
         }
-        if (!mConstrainedLOD) {
+        if (mWindow.hasMipmaps()) {
             throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
         }
 
         initLOD(lod);
+        mSelectedLOD = lod;
+        updateOffsets();
     }
 
     /**
@@ -155,14 +121,38 @@
         if (!mAdaptedAllocation.getType().hasFaces()) {
             throw new RSInvalidStateException("Cannot set Face when the allocation type does not include faces.");
         }
-        if (!mConstrainedFace) {
-            throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
+        if (mWindow.hasFaces()) {
+            throw new RSInvalidStateException("Cannot set face when the adapter includes faces.");
         }
         if (cf == null) {
             throw new RSIllegalArgumentException("Cannot set null face.");
         }
 
         mSelectedFace = cf;
+        updateOffsets();
+    }
+
+
+    /**
+     * @hide
+     * Set the active X.  The x value must be within the range for
+     * the allocation being adapted.
+     *
+     * @param x The x to make active.
+     */
+    public void setX(int x) {
+        if (mAdaptedAllocation.getType().getX() <= x) {
+            throw new RSInvalidStateException("Cannot set X greater than dimension of allocation.");
+        }
+        if (mWindow.getX() == mAdaptedAllocation.getType().getX()) {
+            throw new RSInvalidStateException("Cannot set X when the adapter includes X.");
+        }
+        if ((mWindow.getX() + x) >= mAdaptedAllocation.getType().getX()) {
+            throw new RSInvalidStateException("Cannot set (X + window) which would be larger than dimension of allocation.");
+        }
+
+        mSelectedX = x;
+        updateOffsets();
     }
 
     /**
@@ -179,11 +169,15 @@
         if (mAdaptedAllocation.getType().getY() <= y) {
             throw new RSInvalidStateException("Cannot set Y greater than dimension of allocation.");
         }
-        if (!mConstrainedY) {
+        if (mWindow.getY() == mAdaptedAllocation.getType().getY()) {
             throw new RSInvalidStateException("Cannot set Y when the adapter includes Y.");
         }
+        if ((mWindow.getY() + y) >= mAdaptedAllocation.getType().getY()) {
+            throw new RSInvalidStateException("Cannot set (Y + window) which would be larger than dimension of allocation.");
+        }
 
         mSelectedY = y;
+        updateOffsets();
     }
 
     /**
@@ -200,35 +194,112 @@
         if (mAdaptedAllocation.getType().getZ() <= z) {
             throw new RSInvalidStateException("Cannot set Z greater than dimension of allocation.");
         }
-        if (!mConstrainedZ) {
+        if (mWindow.getZ() == mAdaptedAllocation.getType().getZ()) {
             throw new RSInvalidStateException("Cannot set Z when the adapter includes Z.");
         }
+        if ((mWindow.getZ() + z) >= mAdaptedAllocation.getType().getZ()) {
+            throw new RSInvalidStateException("Cannot set (Z + window) which would be larger than dimension of allocation.");
+        }
 
         mSelectedZ = z;
+        updateOffsets();
+    }
+
+    /**
+     * @hide
+     */
+    public void setArray(int arrayNum, int arrayVal) {
+        if (mAdaptedAllocation.getType().getArray(arrayNum) == 0) {
+            throw new RSInvalidStateException("Cannot set arrayNum when the allocation type does not include arrayNum dim.");
+        }
+        if (mAdaptedAllocation.getType().getArray(arrayNum) <= arrayVal) {
+            throw new RSInvalidStateException("Cannot set arrayNum greater than dimension of allocation.");
+        }
+        if (mWindow.getArray(arrayNum) == mAdaptedAllocation.getType().getArray(arrayNum)) {
+            throw new RSInvalidStateException("Cannot set arrayNum when the adapter includes arrayNum.");
+        }
+        if ((mWindow.getArray(arrayNum) + arrayVal) >= mAdaptedAllocation.getType().getArray(arrayNum)) {
+            throw new RSInvalidStateException("Cannot set (arrayNum + window) which would be larger than dimension of allocation.");
+        }
+
+        mSelectedArray[arrayNum] = arrayVal;
+        updateOffsets();
     }
 
     static public AllocationAdapter create1D(RenderScript rs, Allocation a) {
         rs.validate();
-        AllocationAdapter aa = new AllocationAdapter(0, rs, a);
-        aa.mConstrainedLOD = true;
-        aa.mConstrainedFace = true;
-        aa.mConstrainedY = true;
-        aa.mConstrainedZ = true;
-        aa.initLOD(0);
-        return aa;
+        Type t = Type.createX(rs, a.getElement(), a.getType().getX());
+        return createTyped(rs, a, t);
     }
 
+
     static public AllocationAdapter create2D(RenderScript rs, Allocation a) {
         rs.validate();
-        AllocationAdapter aa = new AllocationAdapter(0, rs, a);
-        aa.mConstrainedLOD = true;
-        aa.mConstrainedFace = true;
-        aa.mConstrainedY = false;
-        aa.mConstrainedZ = true;
-        aa.initLOD(0);
-        return aa;
+        Type t = Type.createXY(rs, a.getElement(), a.getType().getX(), a.getType().getY());
+        return createTyped(rs, a, t);
     }
 
+    /**
+     * @hide
+     *
+     * Create an arbitrary window into the base allocation
+     * The type describes the shape of the window.
+     *
+     * Any dimensions present in the type must be equal or smaller
+     * to the dimensions in the source allocation.  A dimension
+     * present in the allocation that is not present in the type
+     * will be constrained away with the selectors
+     *
+     * If a dimension is present in the type and allcation one of
+     * two things will happen
+     *
+     * If the type is smaller than the allocation a window will be
+     * created, the selected value in the adapter for that dimension
+     * will act as the base address and the type will describe the
+     * size of the view starting at that point.
+     *
+     * If the type and allocation dimension are of the same size
+     * then setting the selector for the dimension will be an error.
+     */
+    static public AllocationAdapter createTyped(RenderScript rs, Allocation a, Type t) {
+        rs.validate();
+
+        if (a.mAdaptedAllocation != null) {
+            throw new RSInvalidStateException("Adapters cannot be nested.");
+        }
+
+        if (!a.getType().getElement().equals(t.getElement())) {
+            throw new RSInvalidStateException("Element must match Allocation type.");
+        }
+
+        if (t.hasFaces() || t.hasMipmaps()) {
+            throw new RSInvalidStateException("Adapters do not support window types with Mipmaps or Faces.");
+        }
+
+        Type at = a.getType();
+        if ((t.getX() > at.getX()) ||
+            (t.getY() > at.getY()) ||
+            (t.getZ() > at.getZ()) ||
+            (t.getArrayCount() > at.getArrayCount())) {
+
+            throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+        }
+
+        if (t.getArrayCount() > 0) {
+            for (int i = 0; i < t.getArray(i); i++) {
+                if (t.getArray(i) > at.getArray(i)) {
+                    throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+                }
+            }
+        }
+
+        // Create the object
+        long id = rs.nAllocationAdapterCreate(a.getID(rs), t.getID(rs));
+        if (id == 0) {
+            throw new RSRuntimeException("AllocationAdapter creation failed.");
+        }
+        return new AllocationAdapter(id, rs, a, t);
+    }
 
     /**
      * Override the Allocation resize.  Resizing adapters is not
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 20b07e7..0f967fc 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -241,8 +241,7 @@
                 addI64(0);
                 addI64(0);
                 addI64(0);
-            }
-            else {
+            } else {
                 addI32((int)obj.getID(null));
             }
         } else {
@@ -619,6 +618,289 @@
         return mPos;
     }
 
+    private static void addToPack(FieldPacker fp, Object obj) {
+        if (obj instanceof Boolean) {
+            fp.addBoolean(((Boolean)obj).booleanValue());
+            return;
+        }
+
+        if (obj instanceof Byte) {
+            fp.addI8(((Byte)obj).byteValue());
+            return;
+        }
+
+        if (obj instanceof Short) {
+            fp.addI16(((Short)obj).shortValue());
+            return;
+        }
+
+        if (obj instanceof Integer) {
+            fp.addI32(((Integer)obj).intValue());
+            return;
+        }
+
+        if (obj instanceof Long) {
+            fp.addI64(((Long)obj).longValue());
+            return;
+        }
+
+        if (obj instanceof Float) {
+            fp.addF32(((Float)obj).floatValue());
+            return;
+        }
+
+        if (obj instanceof Double) {
+            fp.addF64(((Double)obj).doubleValue());
+            return;
+        }
+
+        if (obj instanceof Byte2) {
+            fp.addI8((Byte2)obj);
+            return;
+        }
+
+        if (obj instanceof Byte3) {
+            fp.addI8((Byte3)obj);
+            return;
+        }
+
+        if (obj instanceof Byte4) {
+            fp.addI8((Byte4)obj);
+            return;
+        }
+
+        if (obj instanceof Short2) {
+            fp.addI16((Short2)obj);
+            return;
+        }
+
+        if (obj instanceof Short3) {
+            fp.addI16((Short3)obj);
+            return;
+        }
+
+        if (obj instanceof Short4) {
+            fp.addI16((Short4)obj);
+            return;
+        }
+
+        if (obj instanceof Int2) {
+            fp.addI32((Int2)obj);
+            return;
+        }
+
+        if (obj instanceof Int3) {
+            fp.addI32((Int3)obj);
+            return;
+        }
+
+        if (obj instanceof Int4) {
+            fp.addI32((Int4)obj);
+            return;
+        }
+
+        if (obj instanceof Long2) {
+            fp.addI64((Long2)obj);
+            return;
+        }
+
+        if (obj instanceof Long3) {
+            fp.addI64((Long3)obj);
+            return;
+        }
+
+        if (obj instanceof Long4) {
+            fp.addI64((Long4)obj);
+            return;
+        }
+
+        if (obj instanceof Float2) {
+            fp.addF32((Float2)obj);
+            return;
+        }
+
+        if (obj instanceof Float3) {
+            fp.addF32((Float3)obj);
+            return;
+        }
+
+        if (obj instanceof Float4) {
+            fp.addF32((Float4)obj);
+            return;
+        }
+
+        if (obj instanceof Double2) {
+            fp.addF64((Double2)obj);
+            return;
+        }
+
+        if (obj instanceof Double3) {
+            fp.addF64((Double3)obj);
+            return;
+        }
+
+        if (obj instanceof Double4) {
+            fp.addF64((Double4)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix2f) {
+            fp.addMatrix((Matrix2f)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix3f) {
+            fp.addMatrix((Matrix3f)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix4f) {
+            fp.addMatrix((Matrix4f)obj);
+            return;
+        }
+
+        if (obj instanceof BaseObj) {
+            fp.addObj((BaseObj)obj);
+            return;
+        }
+    }
+
+    private static int getPackedSize(Object obj) {
+        if (obj instanceof Boolean) {
+            return 1;
+        }
+
+        if (obj instanceof Byte) {
+            return 1;
+        }
+
+        if (obj instanceof Short) {
+            return 2;
+        }
+
+        if (obj instanceof Integer) {
+            return 4;
+        }
+
+        if (obj instanceof Long) {
+            return 8;
+        }
+
+        if (obj instanceof Float) {
+            return 4;
+        }
+
+        if (obj instanceof Double) {
+            return 8;
+        }
+
+        if (obj instanceof Byte2) {
+            return 2;
+        }
+
+        if (obj instanceof Byte3) {
+            return 3;
+        }
+
+        if (obj instanceof Byte4) {
+            return 4;
+        }
+
+        if (obj instanceof Short2) {
+            return 4;
+        }
+
+        if (obj instanceof Short3) {
+            return 6;
+        }
+
+        if (obj instanceof Short4) {
+            return 8;
+        }
+
+        if (obj instanceof Int2) {
+            return 8;
+        }
+
+        if (obj instanceof Int3) {
+            return 12;
+        }
+
+        if (obj instanceof Int4) {
+            return 16;
+        }
+
+        if (obj instanceof Long2) {
+            return 16;
+        }
+
+        if (obj instanceof Long3) {
+            return 24;
+        }
+
+        if (obj instanceof Long4) {
+            return 32;
+        }
+
+        if (obj instanceof Float2) {
+            return 8;
+        }
+
+        if (obj instanceof Float3) {
+            return 12;
+        }
+
+        if (obj instanceof Float4) {
+            return 16;
+        }
+
+        if (obj instanceof Double2) {
+            return 16;
+        }
+
+        if (obj instanceof Double3) {
+            return 24;
+        }
+
+        if (obj instanceof Double4) {
+            return 32;
+        }
+
+        if (obj instanceof Matrix2f) {
+            return 16;
+        }
+
+        if (obj instanceof Matrix3f) {
+            return 36;
+        }
+
+        if (obj instanceof Matrix4f) {
+            return 64;
+        }
+
+        if (obj instanceof BaseObj) {
+            if (RenderScript.sPointerSize == 8) {
+                return 32;
+            } else {
+                return 4;
+            }
+        }
+
+        return 0;
+    }
+
+    static FieldPacker createFieldPack(Object[] args) {
+        int len = 0;
+        for (Object arg : args) {
+            len += getPackedSize(arg);
+        }
+        FieldPacker fp = new FieldPacker(len);
+        for (Object arg : args) {
+            addToPack(fp, arg);
+        }
+        return fp;
+    }
+
     private final byte mData[];
     private int mPos;
     private int mLen;
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 271fe05..5e150e9 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -313,6 +313,15 @@
           sizes, depClosures, depFieldIDs);
     }
 
+    native long rsnInvokeClosureCreate(long con, long invokeID, byte[] params,
+        long[] fieldIDs, long[] values, int[] sizes);
+    synchronized long nInvokeClosureCreate(long invokeID, byte[] params,
+        long[] fieldIDs, long[] values, int[] sizes) {
+      validate();
+      return rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
+          values, sizes);
+    }
+
     native void rsnClosureSetArg(long con, long closureID, int index,
       long value, int size);
     synchronized void nClosureSetArg(long closureID, int index, long value,
@@ -330,10 +339,10 @@
       rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
     }
 
-    native long rsnScriptGroup2Create(long con, long[] closures);
-    synchronized long nScriptGroup2Create(long[] closures) {
+    native long rsnScriptGroup2Create(long con, String cachePath, long[] closures);
+    synchronized long nScriptGroup2Create(String cachePath, long[] closures) {
       validate();
-      return rsnScriptGroup2Create(mContext, closures);
+      return rsnScriptGroup2Create(mContext, cachePath, closures);
     }
 
     native void rsnScriptGroup2Execute(long con, long groupID);
@@ -582,6 +591,20 @@
         rsnAllocationResize1D(mContext, id, dimX);
     }
 
+    native long  rsnAllocationAdapterCreate(long con, long allocId, long typeId);
+    synchronized long nAllocationAdapterCreate(long allocId, long typeId) {
+        validate();
+        return rsnAllocationAdapterCreate(mContext, allocId, typeId);
+    }
+
+    native void  rsnAllocationAdapterOffset(long con, long id, int x, int y, int z,
+                                            int mip, int face, int a1, int a2, int a3, int a4);
+    synchronized void nAllocationAdapterOffset(long id, int x, int y, int z,
+                                               int mip, int face, int a1, int a2, int a3, int a4) {
+        validate();
+        rsnAllocationAdapterOffset(mContext, id, x, y, z, mip, face, a1, a2, a3, a4);
+    }
+
     native long rsnFileA3DCreateFromAssetStream(long con, long assetStream);
     synchronized long nFileA3DCreateFromAssetStream(long assetStream) {
         validate();
@@ -745,6 +768,12 @@
         return rsnScriptKernelIDCreate(mContext, sid, slot, sig);
     }
 
+    native long  rsnScriptInvokeIDCreate(long con, long sid, int slot);
+    synchronized long nScriptInvokeIDCreate(long sid, int slot) {
+        validate();
+        return rsnScriptInvokeIDCreate(mContext, sid, slot);
+    }
+
     native long  rsnScriptFieldIDCreate(long con, long sid, int slot);
     synchronized long nScriptFieldIDCreate(long sid, int slot) {
         validate();
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index eb1687a..d352130 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -66,6 +66,46 @@
     }
 
     /**
+     * @hide Pending API review
+     * InvokeID is an identifier for an invoke function. It is used
+     * as an identifier for ScriptGroup creation.
+     *
+     * This class should not be directly created. Instead use the method in the
+     * reflected or intrinsic code "getInvokeID_funcname()".
+     *
+     */
+    public static final class InvokeID extends BaseObj {
+        Script mScript;
+        int mSlot;
+        InvokeID(long id, RenderScript rs, Script s, int slot) {
+            super(id, rs);
+            mScript = s;
+            mSlot = slot;
+        }
+    }
+
+    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
+    /**
+     * @hide Pending API review
+     * Only to be used by generated reflected classes.
+     */
+    protected InvokeID createInvokeID(int slot) {
+        InvokeID i = mIIDs.get(slot);
+        if (i != null) {
+            return i;
+        }
+
+        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
+        if (id == 0) {
+            throw new RSDriverException("Failed to create KernelID");
+        }
+
+        i = new InvokeID(id, mRS, this, slot);
+        mIIDs.put(slot, i);
+        return i;
+    }
+
+    /**
      * FieldID is an identifier for a Script + exported field pair. It is used
      * as an identifier for ScriptGroup creation.
      *
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
index dcad787..113b896 100644
--- a/rs/java/android/renderscript/ScriptGroup2.java
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -8,9 +8,6 @@
 import java.util.Map;
 
 /**
-   @hide Pending Android public API approval.
- */
-/**
 
 ******************************
 You have tried to change the API from what has been previously approved.
@@ -37,6 +34,8 @@
     private Future mReturnFuture;
     private Map<Script.FieldID, Future> mGlobalFuture;
 
+    private FieldPacker mFP;
+
     private static final String TAG = "Closure";
 
     public Closure(long id, RenderScript rs) {
@@ -92,6 +91,44 @@
       setID(id);
     }
 
+    public Closure(RenderScript rs, Script.InvokeID invokeID,
+        Object[] args, Map<Script.FieldID, Object> globals) {
+      super(0, rs);
+      mFP = FieldPacker.createFieldPack(args);
+
+      mBindings = new HashMap<Script.FieldID, Object>();
+      mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+      int numValues = globals.size();
+
+      long[] fieldIDs = new long[numValues];
+      long[] values = new long[numValues];
+      int[] sizes = new int[numValues];
+      long[] depClosures = new long[numValues];
+      long[] depFieldIDs = new long[numValues];
+
+      int i = 0;
+      for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+        Object obj = entry.getValue();
+        Script.FieldID fieldID = entry.getKey();
+        fieldIDs[i] = fieldID.getID(rs);
+        if (obj instanceof UnboundValue) {
+          UnboundValue unbound = (UnboundValue)obj;
+          unbound.addReference(this, fieldID);
+        } else {
+          // TODO(yangni): Verify obj not a future.
+          retrieveValueAndDependenceInfo(rs, i, obj, values,
+              sizes, depClosures, depFieldIDs);
+        }
+        i++;
+      }
+
+      long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs,
+          values, sizes);
+
+      setID(id);
+    }
+
     private static void retrieveValueAndDependenceInfo(RenderScript rs,
         int index, Object obj, long[] values, int[] sizes, long[] depClosures,
         long[] depFieldIDs) {
@@ -102,6 +139,12 @@
         depClosures[index] = f.getClosure().getID(rs);
         Script.FieldID fieldID = f.getFieldID();
         depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
+        if (obj == null) {
+          // Value is originally created by the owner closure
+          values[index] = 0;
+          sizes[index] = 0;
+          return;
+        }
       } else {
         depClosures[index] = 0;
         depFieldIDs[index] = 0;
@@ -124,6 +167,10 @@
       Future f = mGlobalFuture.get(field);
 
       if (f == null) {
+        // If the field is not bound to this closure, this will return a future
+        // without an associated value (reference). So this is not working for
+        // cross-module (cross-script) linking in this case where a field not
+        // explicitly bound.
         f = new Future(this, field, mBindings.get(field));
         mGlobalFuture.put(field, f);
       }
@@ -163,7 +210,6 @@
           size = 8;
         }
       }
-
       public long value;
       public int size;
     }
@@ -240,12 +286,10 @@
     for (int i = 0; i < closureIDs.length; i++) {
       closureIDs[i] = closures.get(i).getID(rs);
     }
-    long id = rs.nScriptGroup2Create(closureIDs);
+    long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs);
     setID(id);
   }
 
-  // TODO: If this was reflected method, we could enforce the number of
-  // arguments.
   public Object[] execute(Object... inputs) {
     if (inputs.length < mInputs.size()) {
       Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
@@ -302,6 +346,13 @@
       return c;
     }
 
+    public Closure addInvoke(Script.InvokeID invoke, Object[] args,
+        Map<Script.FieldID, Object> globalBindings) {
+      Closure c = new Closure(mRS, invoke, args, globalBindings);
+      mClosures.add(c);
+      return c;
+    }
+
     public UnboundValue addInput() {
       UnboundValue unbound = new UnboundValue();
       mInputs.add(unbound);
@@ -309,8 +360,6 @@
     }
 
     public ScriptGroup2 create(Future... outputs) {
-      // TODO: Save all script groups that have been created and return one that was
-      // saved and matches the outputs.
       ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
       return ret;
     }
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index 98aeaa9..a58e42c 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -52,6 +52,9 @@
     int mDimYuv;
     int mElementCount;
     Element mElement;
+    int mArrays[];
+
+    static final int mMaxArrays = 4;
 
     public enum CubemapFace {
         POSITIVE_X (0),
@@ -146,6 +149,30 @@
         return mElementCount;
     }
 
+    /**
+     * @hide
+     */
+    public int getArray(int dim) {
+        if ((dim < 0) || (dim >= mMaxArrays)) {
+            throw new RSIllegalArgumentException("Array dimension out of range.");
+        }
+
+        if (mArrays == null || dim >= mArrays.length) {
+            // Dimension in range but no array for that dimension allocated
+            return 0;
+        }
+
+        return mArrays[dim];
+    }
+
+    /**
+     * @hide
+     */
+    public int getArrayCount() {
+        if (mArrays != null) return mArrays.length;
+        return 0;
+    }
+
     void calcElementCount() {
         boolean hasLod = hasMipmaps();
         int x = getX();
@@ -180,6 +207,13 @@
 
             count += x * y * z * faces;
         }
+
+        if (mArrays != null) {
+            for (int ct = 0; ct < mArrays.length; ct++) {
+                count *= mArrays[ct];
+            }
+        }
+
         mElementCount = count;
     }
 
@@ -296,6 +330,7 @@
         boolean mDimMipmaps;
         boolean mDimFaces;
         int mYuv;
+        int[] mArray = new int[mMaxArrays];
 
         Element mElement;
 
@@ -341,6 +376,22 @@
             return this;
         }
 
+        /**
+         * @hide
+         *
+         * @param dim
+         * @param value
+         *
+         * @return Builder
+         */
+        public Builder setArray(int dim, int value) {
+            if(dim < 0 || dim >= mMaxArrays) {
+                throw new RSIllegalArgumentException("Array dimension out of range.");
+            }
+            mArray[dim] = value;
+            return this;
+        }
+
         public Builder setMipmaps(boolean value) {
             mDimMipmaps = value;
             return this;
@@ -405,6 +456,16 @@
                 }
             }
 
+            int[] arrays = null;
+            for (int ct = mMaxArrays - 1; ct >= 0; ct--) {
+                if (mArray[ct] != 0 && arrays == null) {
+                    arrays = new int[ct];
+                }
+                if ((mArray[ct] == 0) && (arrays != null)) {
+                    throw new RSInvalidStateException("Array dimensions must be contigous from 0.");
+                }
+            }
+
             long id = mRS.nTypeCreate(mElement.getID(mRS),
                                      mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
             Type t = new Type(id, mRS);
@@ -415,6 +476,7 @@
             t.mDimMipmaps = mDimMipmaps;
             t.mDimFaces = mDimFaces;
             t.mDimYuv = mYuv;
+            t.mArrays = arrays;
 
             t.calcElementCount();
             return t;
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 06f4def..198cabe 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -242,6 +242,37 @@
       depFieldIDs, (size_t)depFieldIDs_length);
 }
 
+static jlong
+nInvokeClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong invokeID,
+                     jbyteArray paramArray, jlongArray fieldIDArray, jlongArray valueArray,
+                     jintArray sizeArray) {
+  jbyte* jParams = _env->GetByteArrayElements(paramArray, nullptr);
+  jsize jParamLength = _env->GetArrayLength(paramArray);
+
+  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
+  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
+  RsScriptFieldID* fieldIDs =
+      (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * fieldIDs_length);
+  for (int i = 0; i< fieldIDs_length; i++) {
+    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
+  }
+
+  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
+  jsize values_length = _env->GetArrayLength(valueArray);
+  uintptr_t* values = (uintptr_t*)alloca(sizeof(uintptr_t) * values_length);
+  for (int i = 0; i < values_length; i++) {
+    values[i] = (uintptr_t)jValues[i];
+  }
+
+  jint* sizes = _env->GetIntArrayElements(sizeArray, nullptr);
+  jsize sizes_length = _env->GetArrayLength(sizeArray);
+
+  return (jlong)(uintptr_t)rsInvokeClosureCreate(
+      (RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
+      fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
+      (size_t*)sizes, (size_t)sizes_length);
+}
+
 static void
 nClosureSetArg(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
                jint index, jlong value, jint size) {
@@ -258,7 +289,9 @@
 
 static long
 nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con,
-                    jlongArray closureArray) {
+                    jstring cacheDir, jlongArray closureArray) {
+  AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
+
   jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
   jsize numClosures = _env->GetArrayLength(closureArray);
   RsClosure* closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures);
@@ -266,8 +299,9 @@
     closures[i] = (RsClosure)jClosures[i];
   }
 
-  return (jlong)(uintptr_t)rsScriptGroup2Create((RsContext)con, closures,
-                                                numClosures);
+  return (jlong)(uintptr_t)rsScriptGroup2Create(
+      (RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length(),
+      closures, numClosures);
 }
 
 static void
@@ -1013,6 +1047,37 @@
     rsAllocationResize1D((RsContext)con, (RsAllocation)alloc, dimX);
 }
 
+
+static jlong
+nAllocationAdapterCreate(JNIEnv *_env, jobject _this, jlong con, jlong basealloc, jlong type)
+{
+    if (kLogApi) {
+        ALOGD("nAllocationAdapterCreate, con(%p), base(%p), type(%p)",
+              (RsContext)con, (RsAllocation)basealloc, (RsElement)type);
+    }
+    return (jlong)(uintptr_t) rsAllocationAdapterCreate((RsContext)con, (RsType)type,
+                                                        (RsAllocation)basealloc);
+
+}
+
+static void
+nAllocationAdapterOffset(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+                        jint x, jint y, jint z, jint face, jint lod,
+                        jint a1, jint a2, jint a3, jint a4)
+{
+    uint32_t params[] = {
+        (uint32_t)x, (uint32_t)y, (uint32_t)z, (uint32_t)face,
+        (uint32_t)lod, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4
+    };
+    if (kLogApi) {
+        ALOGD("nAllocationAdapterOffset, con(%p), alloc(%p), x(%i), y(%i), z(%i), face(%i), lod(%i), arrays(%i %i %i %i)",
+              (RsContext)con, (RsAllocation)alloc, x, y, z, face, lod, a1, a2, a3, a4);
+    }
+    rsAllocationAdapterOffset((RsContext)con, (RsAllocation)alloc,
+                              params, sizeof(params));
+}
+
+
 // -----------------------------------
 
 static jlong
@@ -1485,6 +1550,16 @@
 }
 
 static jlong
+nScriptInvokeIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
+{
+    if (kLogApi) {
+        ALOGD("nScriptInvokeIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con,
+              (void *)sid, slot);
+    }
+    return (jlong)(uintptr_t)rsScriptInvokeIDCreate((RsContext)con, (RsScript)sid, slot);
+}
+
+static jlong
 nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
 {
     if (kLogApi) {
@@ -1932,6 +2007,7 @@
 {"rsnContextResume",                 "(J)V",                                  (void*)nContextResume },
 {"rsnContextSendMessage",            "(JI[I)V",                               (void*)nContextSendMessage },
 {"rsnClosureCreate",                 "(JJJ[J[J[I[J[J)J",                      (void*)nClosureCreate },
+{"rsnInvokeClosureCreate",           "(JJ[B[J[J[I)J",                         (void*)nInvokeClosureCreate },
 {"rsnClosureSetArg",                 "(JJIJI)V",                              (void*)nClosureSetArg },
 {"rsnClosureSetGlobal",              "(JJJJI)V",                              (void*)nClosureSetGlobal },
 {"rsnAssignName",                    "(JJ[B)V",                               (void*)nAssignName },
@@ -1983,6 +2059,9 @@
 {"rsnAllocationResize1D",            "(JJI)V",                                (void*)nAllocationResize1D },
 {"rsnAllocationGenerateMipmaps",     "(JJ)V",                                 (void*)nAllocationGenerateMipmaps },
 
+{"rsnAllocationAdapterCreate",       "(JJJ)J",                                (void*)nAllocationAdapterCreate },
+{"rsnAllocationAdapterOffset",       "(JJIIIIIIIII)V",                        (void*)nAllocationAdapterOffset },
+
 {"rsnScriptBindAllocation",          "(JJJI)V",                               (void*)nScriptBindAllocation },
 {"rsnScriptSetTimeZone",             "(JJ[B)V",                               (void*)nScriptSetTimeZone },
 {"rsnScriptInvoke",                  "(JJI)V",                                (void*)nScriptInvoke },
@@ -2006,9 +2085,10 @@
 {"rsnScriptCCreate",                 "(JLjava/lang/String;Ljava/lang/String;[BI)J",  (void*)nScriptCCreate },
 {"rsnScriptIntrinsicCreate",         "(JIJ)J",                                (void*)nScriptIntrinsicCreate },
 {"rsnScriptKernelIDCreate",          "(JJII)J",                               (void*)nScriptKernelIDCreate },
+{"rsnScriptInvokeIDCreate",          "(JJI)J",                                (void*)nScriptInvokeIDCreate },
 {"rsnScriptFieldIDCreate",           "(JJI)J",                                (void*)nScriptFieldIDCreate },
 {"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
-{"rsnScriptGroup2Create",            "(J[J)J",                                (void*)nScriptGroup2Create },
+{"rsnScriptGroup2Create",            "(JLjava/lang/String;[J)J",               (void*)nScriptGroup2Create },
 {"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
 {"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
 {"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8c314cf..a712d78 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -170,6 +170,8 @@
 
     private final Rect mTempRect = new Rect();
 
+    private final Rect mTempRect1 = new Rect();
+
     private final Point mTempPoint = new Point();
 
     private final PackageManager mPackageManager;
@@ -2535,57 +2537,6 @@
         }
 
         @Override
-        public  boolean computeClickPointInScreen(int accessibilityWindowId,
-                long accessibilityNodeId, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
-                throws RemoteException {
-            final int resolvedWindowId;
-            IAccessibilityInteractionConnection connection = null;
-            Region partialInteractiveRegion = mTempRegion;
-            synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
-                    return false;
-                }
-                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
-                final boolean permissionGranted =
-                        mSecurityPolicy.canRetrieveWindowContentLocked(this);
-                if (!permissionGranted) {
-                    return false;
-                } else {
-                    connection = getConnectionLocked(resolvedWindowId);
-                    if (connection == null) {
-                        return false;
-                    }
-                }
-                if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
-                        resolvedWindowId, partialInteractiveRegion)) {
-                    partialInteractiveRegion = null;
-                }
-            }
-            final int interrogatingPid = Binder.getCallingPid();
-            final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
-            try {
-                connection.computeClickPointInScreen(accessibilityNodeId, partialInteractiveRegion,
-                        interactionId, callback, interrogatingPid, interrogatingTid, spec);
-                return true;
-            } catch (RemoteException re) {
-                if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error computeClickPointInScreen().");
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identityToken);
-            }
-            return false;
-        }
-
-        @Override
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
             synchronized (mLock) {
@@ -3238,38 +3189,36 @@
             }
 
             synchronized (mLock) {
-                Point point = mClient.computeClickPointInScreen(mConnectionId,
-                        focus.getWindowId(), focus.getSourceNodeId());
+                Rect boundsInScreen = mTempRect;
+                focus.getBoundsInScreen(boundsInScreen);
 
-                if (point == null) {
+                // Clip to the window bounds.
+                Rect windowBounds = mTempRect1;
+                getWindowBounds(focus.getWindowId(), windowBounds);
+                boundsInScreen.intersect(windowBounds);
+                if (boundsInScreen.isEmpty()) {
                     return false;
                 }
 
+                // Apply magnification if needed.
                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
                 if (spec != null && !spec.isNop()) {
-                    point.offset((int) -spec.offsetX, (int) -spec.offsetY);
-                    point.x = (int) (point.x * (1 / spec.scale));
-                    point.y = (int) (point.y * (1 / spec.scale));
+                    boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY);
+                    boundsInScreen.scale(1 / spec.scale);
                 }
 
-                // Make sure the point is within the window.
-                Rect windowBounds = mTempRect;
-                getWindowBounds(focus.getWindowId(), windowBounds);
-                if (!windowBounds.contains(point.x, point.y)) {
-                    return false;
-                }
-
-                // Make sure the point is within the screen.
+                // Clip to the screen bounds.
                 Point screenSize = mTempPoint;
                 mDefaultDisplay.getRealSize(screenSize);
-                if (point.x < 0 || point.x > screenSize.x
-                        || point.y < 0 || point.y > screenSize.y) {
+                boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y);
+                if (boundsInScreen.isEmpty()) {
                     return false;
                 }
 
-                outPoint.set(point.x, point.y);
-                return true;
+                outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY());
             }
+
+            return true;
         }
 
         private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index b9ed89b..f18b5ef 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -77,6 +77,10 @@
     private static final int STATE_DELEGATING = 0x00000004;
     private static final int STATE_GESTURE_DETECTING = 0x00000005;
 
+    private static final int CLICK_LOCATION_NONE = 0;
+    private static final int CLICK_LOCATION_ACCESSIBILITY_FOCUS = 1;
+    private static final int CLICK_LOCATION_LAST_TOUCH_EXPLORED = 2;
+
     // The maximum of the cosine between the vectors of two moving
     // pointers so they can be considered moving in the same direction.
     private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
@@ -942,12 +946,16 @@
      *
      * @param prototype The prototype from which to create the injected events.
      * @param policyFlags The policy flags associated with the event.
+     * @param targetAccessibilityFocus Whether the event targets the accessibility focus.
      */
-    private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) {
+    private void sendActionDownAndUp(MotionEvent prototype, int policyFlags,
+            boolean targetAccessibilityFocus) {
         // Tap with the pointer that last explored.
         final int pointerId = prototype.getPointerId(prototype.getActionIndex());
         final int pointerIdBits = (1 << pointerId);
+        prototype.setTargetAccessibilityFocus(targetAccessibilityFocus);
         sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags);
+        prototype.setTargetAccessibilityFocus(targetAccessibilityFocus);
         sendMotionEvent(prototype, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
     }
 
@@ -1155,7 +1163,8 @@
             final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
 
             Point clickLocation = mTempPoint;
-            if (!computeClickLocation(clickLocation)) {
+            final int result = computeClickLocation(clickLocation);
+            if (result == CLICK_LOCATION_NONE) {
                 return;
             }
 
@@ -1171,7 +1180,8 @@
                     secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
                     coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
                     secondTapUp.getSource(), secondTapUp.getFlags());
-            sendActionDownAndUp(event, policyFlags);
+            final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
+            sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
             event.recycle();
         }
 
@@ -1216,7 +1226,7 @@
                 MAX_DRAGGING_ANGLE_COS);
     }
 
-    private boolean computeClickLocation(Point outLocation) {
+    private int computeClickLocation(Point outLocation) {
         MotionEvent lastExploreEvent = mInjectedPointerTracker.getLastInjectedHoverEventForClick();
         if (lastExploreEvent != null) {
             final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
@@ -1224,14 +1234,17 @@
             outLocation.y = (int) lastExploreEvent.getY(lastExplorePointerIndex);
             if (!mAms.accessibilityFocusOnlyInActiveWindow()
                     || mLastTouchedWindowId == mAms.getActiveWindowId()) {
-                mAms.getAccessibilityFocusClickPointInScreen(outLocation);
+                if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
+                    return CLICK_LOCATION_ACCESSIBILITY_FOCUS;
+                } else {
+                    return CLICK_LOCATION_LAST_TOUCH_EXPLORED;
+                }
             }
-            return true;
         }
         if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
-            return true;
+            return CLICK_LOCATION_ACCESSIBILITY_FOCUS;
         }
-        return false;
+        return CLICK_LOCATION_NONE;
     }
 
     /**
@@ -1310,14 +1323,13 @@
                 return;
             }
 
-            int clickLocationX;
-            int clickLocationY;
-
             final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
             final int pointerIndex = mEvent.findPointerIndex(pointerId);
 
             Point clickLocation = mTempPoint;
-            if (!computeClickLocation(clickLocation)) {
+            final int result = computeClickLocation(clickLocation);
+
+            if (result == CLICK_LOCATION_NONE) {
                 return;
             }
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 289152b..4d7ebed 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -382,6 +382,7 @@
                     // we're now good to go, so start the backup alarms
                     if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
                     startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
+                    scheduleNextFullBackupJob();
                 }
             }
         }
@@ -1864,7 +1865,8 @@
     boolean tryBindTransport(ServiceInfo info) {
         try {
             PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
-            if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+            if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                    != 0) {
                 return bindTransport(info);
             } else {
                 Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
@@ -3195,7 +3197,7 @@
                     final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
                     final boolean sendApk = mIncludeApks
                             && !isSharedStorage
-                            && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
+                            && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
                             && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
                                 (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
 
@@ -3853,6 +3855,16 @@
             PackageInfo currentPackage;
 
             try {
+                if (!mEnabled || !mProvisioned) {
+                    // Backups are globally disabled, so don't proceed.
+                    if (DEBUG) {
+                        Slog.i(TAG, "full backup requested but e=" + mEnabled
+                                + " p=" + mProvisioned + "; ignoring");
+                    }
+                    mUpdateSchedule = false;
+                    return;
+                }
+
                 IBackupTransport transport = getTransport(mCurrentTransport);
                 if (transport == null) {
                     Slog.w(TAG, "Transport not present; full data backup not performed");
@@ -4150,6 +4162,17 @@
         long now = System.currentTimeMillis();
         FullBackupEntry entry = null;
 
+        if (!mEnabled || !mProvisioned) {
+            // Backups are globally disabled, so don't proceed.  We also don't reschedule
+            // the job driving automatic backups; that job will be scheduled again when
+            // the user enables backup.
+            if (MORE_DEBUG) {
+                Slog.i(TAG, "beginFullBackup but e=" + mEnabled
+                        + " p=" + mProvisioned + "; ignoring");
+            }
+            return false;
+        }
+
         if (DEBUG_SCHEDULING) {
             Slog.i(TAG, "Beginning scheduled full backup operation");
         }
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 5c45201..1a0fa34 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -9,6 +9,6 @@
     java/com/android/server/EventLogTags.logtags \
     java/com/android/server/am/EventLogTags.logtags
 
-LOCAL_JAVA_LIBRARIES := android.policy telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 45fa373..7d156df 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1230,7 +1230,8 @@
         if (mAlarmBatches.size() > 0) {
             final Batch firstWakeup = findFirstWakeupBatchLocked();
             final Batch firstBatch = mAlarmBatches.get(0);
-            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+            // always update the kernel alarms, as a backstop against missed wakeups
+            if (firstWakeup != null) {
                 mNextWakeup = firstWakeup.start;
                 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
             }
@@ -1243,7 +1244,8 @@
                 nextNonWakeup = mNextNonWakeupDeliveryTime;
             }
         }
-        if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) {
+        // always update the kernel alarm, as a backstop against missed wakeups
+        if (nextNonWakeup != 0) {
             mNextNonWakeup = nextNonWakeup;
             setLocked(ELAPSED_REALTIME, nextNonWakeup);
         }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 42a5195..17b4939 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -813,7 +813,8 @@
                                 .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
                         if (appInfo != null) {
                             pkgUid = appInfo.uid;
-                            isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+                            isPrivileged = (appInfo.privateFlags
+                                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
                         } else {
                             if ("media".equals(packageName)) {
                                 pkgUid = Process.MEDIA_UID;
@@ -996,7 +997,8 @@
                     ApplicationInfo appInfo = ActivityThread.getPackageManager()
                             .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
                     if (appInfo != null) {
-                        isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+                        isPrivileged = (appInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
                     }
                 } else {
                     // Could not load data, don't add to cache so it will be loaded later.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 944f1c0..b72b29d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -832,6 +832,19 @@
         }
     };
 
+    private Network[] getVpnUnderlyingNetworks(int uid) {
+        if (!mLockdownEnabled) {
+            int user = UserHandle.getUserId(uid);
+            synchronized (mVpns) {
+                Vpn vpn = mVpns.get(user);
+                if (vpn != null && vpn.appliesToUid(uid)) {
+                    return vpn.getUnderlyingNetworks();
+                }
+            }
+        }
+        return null;
+    }
+
     private NetworkState getUnfilteredActiveNetworkState(int uid) {
         NetworkInfo info = null;
         LinkProperties lp = null;
@@ -841,25 +854,17 @@
 
         NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId);
 
-        if (!mLockdownEnabled) {
-            int user = UserHandle.getUserId(uid);
-            synchronized (mVpns) {
-                Vpn vpn = mVpns.get(user);
-                if (vpn != null && vpn.appliesToUid(uid)) {
-                    // getUnderlyingNetworks() returns:
-                    // null => the VPN didn't specify anything, so we use the default.
-                    // empty array => the VPN explicitly said "no default network".
-                    // non-empty array => the VPN specified one or more default networks; we use the
-                    //                    first one.
-                    Network[] networks = vpn.getUnderlyingNetworks();
-                    if (networks != null) {
-                        if (networks.length > 0) {
-                            nai = getNetworkAgentInfoForNetwork(networks[0]);
-                        } else {
-                            nai = null;
-                        }
-                    }
-                }
+        final Network[] networks = getVpnUnderlyingNetworks(uid);
+        if (networks != null) {
+            // getUnderlyingNetworks() returns:
+            // null => there was no VPN, or the VPN didn't specify anything, so we use the default.
+            // empty array => the VPN explicitly said "no default network".
+            // non-empty array => the VPN specified one or more default networks; we use the
+            //                    first one.
+            if (networks.length > 0) {
+                nai = getNetworkAgentInfoForNetwork(networks[0]);
+            } else {
+                nai = null;
             }
         }
 
@@ -990,6 +995,15 @@
     public NetworkInfo getNetworkInfo(int networkType) {
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
+        if (getVpnUnderlyingNetworks(uid) != null) {
+            // A VPN is active, so we may need to return one of its underlying networks. This
+            // information is not available in LegacyTypeTracker, so we have to get it from
+            // getUnfilteredActiveNetworkState.
+            NetworkState state = getUnfilteredActiveNetworkState(uid);
+            if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
+                return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+            }
+        }
         NetworkState state = getFilteredNetworkState(networkType, uid);
         return state.networkInfo;
     }
@@ -2622,9 +2636,15 @@
 
     // 100 percent is full good, 0 is full bad.
     public void reportInetCondition(int networkType, int percentage) {
-        if (percentage > 50) return;  // don't handle good network reports
         NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
-        if (nai != null) reportBadNetwork(nai.network);
+        if (nai == null) return;
+        boolean isGood = percentage > 50;
+        // Revalidate if the app report does not match our current validated state.
+        if (isGood != nai.lastValidated) {
+            // Make the message logged by reportBadNetwork below less confusing.
+            if (DBG && isGood) log("reportInetCondition: type=" + networkType + " ok, revalidate");
+            reportBadNetwork(nai.network);
+        }
     }
 
     public void reportBadNetwork(Network network) {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 1405fc1..1e3b46b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -892,11 +892,6 @@
         // Temporary workaround for http://b/17945169.
         Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
         SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
-
-        // TODO: Stop setting these properties once we've removed all
-        // references to them.
-        SystemProperties.set("persist.sys.language", locale.getLanguage());
-        SystemProperties.set("persist.sys.country", locale.getCountry());
     }
 
     /**
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index d1b4569..aeacd45 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -31,6 +31,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Handler;
@@ -63,7 +64,7 @@
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
     private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    int mNightMode = UiModeManager.MODE_NIGHT_NO;
+    private int mNightMode = UiModeManager.MODE_NIGHT_NO;
 
     private boolean mCarModeEnabled = false;
     private boolean mCharging = false;
@@ -157,6 +158,7 @@
     public void onStart() {
         final Context context = getContext();
         mTwilightManager = getLocalService(TwilightManager.class);
+
         final PowerManager powerManager =
                 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
@@ -168,20 +170,23 @@
 
         mConfiguration.setToDefaults();
 
-        mDefaultUiModeType = context.getResources().getInteger(
+        final Resources res = context.getResources();
+        mDefaultUiModeType = res.getInteger(
                 com.android.internal.R.integer.config_defaultUiModeType);
-        mCarModeKeepsScreenOn = (context.getResources().getInteger(
+        mCarModeKeepsScreenOn = (res.getInteger(
                 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
-        mDeskModeKeepsScreenOn = (context.getResources().getInteger(
+        mDeskModeKeepsScreenOn = (res.getInteger(
                 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
-        mTelevision = context.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_TELEVISION) ||
-            context.getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_LEANBACK);
-        mWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
 
+        final PackageManager pm = context.getPackageManager();
+        mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+        mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+
+        final int defaultNightMode = res.getInteger(
+                com.android.internal.R.integer.config_defaultNightMode);
         mNightMode = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
+                Settings.Secure.UI_NIGHT_MODE, defaultNightMode);
 
         mTwilightManager.registerListener(mTwilightListener, mHandler);
 
@@ -245,7 +250,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    if (isDoingNightModeLocked() && mNightMode != mode) {
+                    if (mNightMode != mode) {
                         Settings.Secure.putInt(getContext().getContentResolver(),
                                 Settings.Secure.UI_NIGHT_MODE, mode);
                         mNightMode = mode;
@@ -309,10 +314,6 @@
         }
     }
 
-    boolean isDoingNightModeLocked() {
-        return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    }
-
     void setCarModeLocked(boolean enabled, int flags) {
         if (mCarModeEnabled != enabled) {
             mCarModeEnabled = enabled;
@@ -354,17 +355,13 @@
         } else if (isDeskDockState(mDockState)) {
             uiMode = Configuration.UI_MODE_TYPE_DESK;
         }
-        if (mCarModeEnabled) {
-            if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                updateComputedNightModeLocked();
-                uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
-                        : Configuration.UI_MODE_NIGHT_NO;
-            } else {
-                uiMode |= mNightMode << 4;
-            }
+
+        if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+            updateComputedNightModeLocked();
+            uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
+                    : Configuration.UI_MODE_NIGHT_NO;
         } else {
-            // Disabling the car mode clears the night mode.
-            uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO;
+            uiMode |= mNightMode << 4;
         }
 
         if (LOG) {
@@ -618,7 +615,7 @@
 
     void updateTwilight() {
         synchronized (mLock) {
-            if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+            if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
                 updateComputedNightModeLocked();
                 updateLocked(0, 0);
             }
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index bffbb4c2..c9a83ec 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -219,6 +219,7 @@
 
         mWakeLock.acquire();
 
+        Log.i(TAG, "MSG_NEW_DEVICE_STATE ");
         Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
                 mHeadsetState, newName);
         mHandler.sendMessage(msg);
@@ -286,14 +287,16 @@
                 return;
             }
 
-            if (LOG)
-                Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected"));
+            if (LOG) {
+                Slog.v(TAG, "headsetName: " + headsetName +
+                        (state == 1 ? " connected" : " disconnected"));
+            }
 
             if (outDevice != 0) {
-              mAudioManager.setWiredDeviceConnectionState(outDevice, state, headsetName);
+              mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
             }
             if (inDevice != 0) {
-              mAudioManager.setWiredDeviceConnectionState(inDevice, state, headsetName);
+              mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
             }
         }
     }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e52b2bf..9339b35 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3083,7 +3083,8 @@
             try {
                 PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
                 if (packageInfo != null
-                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+                        && (packageInfo.applicationInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                     return true;
                 }
             } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b5d2720..a437761 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -87,6 +87,7 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.WindowManagerService;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -169,6 +170,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPermissionController;
+import android.os.IProcessInfoService;
 import android.os.IRemoteCallback;
 import android.os.IUserManager;
 import android.os.Looper;
@@ -1854,9 +1856,14 @@
                     synchronized (ActivityManagerService.this) {
                         if (DEBUG_PSS) Slog.d(TAG, "Collected native and kernel memory in "
                                 + (SystemClock.uptimeMillis()-start) + "ms");
-                        mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
-                                memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
-                                memInfo.getKernelUsedSizeKb(), nativeTotalPss);
+                        final long cachedKb = memInfo.getCachedSizeKb();
+                        final long freeKb = memInfo.getFreeSizeKb();
+                        final long zramKb = memInfo.getZramTotalSizeKb();
+                        final long kernelKb = memInfo.getKernelUsedSizeKb();
+                        EventLogTags.writeAmMeminfo(cachedKb*1024, freeKb*1024, zramKb*1024,
+                                kernelKb*1024, nativeTotalPss*1024);
+                        mProcessStats.addSysMemUsageLocked(cachedKb, freeKb, zramKb, kernelKb,
+                                nativeTotalPss);
                     }
                 }
 
@@ -1914,6 +1921,7 @@
                 ServiceManager.addService("cpuinfo", new CpuBinder(this));
             }
             ServiceManager.addService("permission", new PermissionController(this));
+            ServiceManager.addService("processinfo", new ProcessInfoService(this));
 
             ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                     "android", STOCK_PM_FLAGS);
@@ -3723,6 +3731,10 @@
             if (r == null) {
                 return;
             }
+            if (r.task != null && r.task.mResizeable) {
+                // Fixed screen orientation isn't supported with resizeable activities.
+                return;
+            }
             final long origId = Binder.clearCallingIdentity();
             mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -5617,7 +5629,10 @@
 
     @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        enforceNotIsolatedCaller("showBootMessage");
+        if (Binder.getCallingUid() != Process.myUid()) {
+            // These days only the core system can call this, so apps can't get in
+            // the way of what we show about running them.
+        }
         mWindowManager.showBootMessage(msg, always);
     }
 
@@ -6236,7 +6251,7 @@
                 "setProcessForeground()");
         synchronized(this) {
             boolean changed = false;
-            
+
             synchronized (mPidsSelfLocked) {
                 ProcessRecord pr = mPidsSelfLocked.get(pid);
                 if (pr == null && isForeground) {
@@ -6272,13 +6287,52 @@
                     }
                 }
             }
-            
+
             if (changed) {
                 updateOomAdjLocked();
             }
         }
     }
-    
+
+    // =========================================================
+    // PROCESS INFO
+    // =========================================================
+
+    static class ProcessInfoService extends IProcessInfoService.Stub {
+        final ActivityManagerService mActivityManagerService;
+        ProcessInfoService(ActivityManagerService activityManagerService) {
+            mActivityManagerService = activityManagerService;
+        }
+
+        @Override
+        public void getProcessStatesFromPids(/*in*/ int[] pids, /*out*/ int[] states) {
+            mActivityManagerService.getProcessStatesForPIDs(/*in*/ pids, /*out*/ states);
+        }
+    }
+
+    /**
+     * For each PID in the given input array, write the current process state
+     * for that process into the output array, or -1 to indicate that no
+     * process with the given PID exists.
+     */
+    public void getProcessStatesForPIDs(/*in*/ int[] pids, /*out*/ int[] states) {
+        if (pids == null) {
+            throw new NullPointerException("pids");
+        } else if (states == null) {
+            throw new NullPointerException("states");
+        } else if (pids.length != states.length) {
+            throw new IllegalArgumentException("input and output arrays have different lengths!");
+        }
+
+        synchronized (mPidsSelfLocked) {
+            for (int i = 0; i < pids.length; i++) {
+                ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
+                states[i] = (pr == null) ? ActivityManager.PROCESS_STATE_NONEXISTENT :
+                        pr.curProcState;
+            }
+        }
+    }
+
     // =========================================================
     // PERMISSIONS
     // =========================================================
@@ -6328,7 +6382,7 @@
      * permission is automatically denied.  (Internally a null permission
      * string is used when calling {@link #checkComponentPermission} in cases
      * when only uid-based security is needed.)
-     * 
+     *
      * This can be called with or without the global lock held.
      */
     @Override
@@ -6605,12 +6659,12 @@
             if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                     "Checking grant " + targetPkg + " permission to " + grantUri);
         }
-        
+
         final IPackageManager pm = AppGlobals.getPackageManager();
 
         // If this is not a content: uri, we can't do anything with it.
         if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
-            if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                     "Can't grant URI permission for non-content URI: " + grantUri);
             return -1;
         }
@@ -6738,7 +6792,7 @@
         // to the uri, and the target doesn't.  Let's now give this to
         // the target.
 
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                 "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
 
         final String authority = grantUri.uri.getAuthority();
@@ -6940,7 +6994,7 @@
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
                     perm.targetUid);
             if (perms != null) {
-                if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                         "Removing " + perm.targetUid + " permission to " + perm.uri);
 
                 perms.remove(perm.uri);
@@ -7053,7 +7107,6 @@
                 return;
             }
 
-            final IPackageManager pm = AppGlobals.getPackageManager();
             final String authority = uri.getAuthority();
             final ProviderInfo pi = getProviderInfoLocked(authority, userId);
             if (pi == null) {
@@ -7822,6 +7875,22 @@
     }
 
     @Override
+    public void setTaskResizeable(int taskId, boolean resizeable) {
+        synchronized (this) {
+            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+            if (task == null) {
+                Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
+                return;
+            }
+            if (task.mResizeable != resizeable) {
+                task.mResizeable = resizeable;
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+                mStackSupervisor.resumeTopActivitiesLocked();
+            }
+        }
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filename) {
         if (!FileUtils.isValidExtFilename(filename)
                 || !filename.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
@@ -8164,7 +8233,7 @@
     @Override
     public void resizeStack(int stackId, Rect bounds) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "resizeStackBox()");
+                "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9059,7 +9128,7 @@
             }
         }
     }
-    
+
     public final void publishContentProviders(IApplicationThread caller,
             List<ContentProviderHolder> providers) {
         if (providers == null) {
@@ -9642,7 +9711,7 @@
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.STOP_APP_SWITCHES);
         }
-        
+
         synchronized(this) {
             mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
                     + APP_SWITCH_DELAY_TIME;
@@ -9652,14 +9721,14 @@
             mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
         }
     }
-    
+
     public void resumeAppSwitches() {
         if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.STOP_APP_SWITCHES);
         }
-        
+
         synchronized(this) {
             // Note that we don't execute any pending app switches... we will
             // let those wait until either the timeout, or the next start
@@ -9667,7 +9736,7 @@
             mAppSwitchesAllowedTime = 0;
         }
     }
-    
+
     boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
             int callingPid, int callingUid, String name) {
         if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -9695,7 +9764,7 @@
         Slog.w(TAG, name + " request from " + sourceUid + " stopped");
         return false;
     }
-    
+
     public void setDebugApp(String packageName, boolean waitForDebugger,
             boolean persistent) {
         enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
@@ -10036,7 +10105,7 @@
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(true);
                 if (translucentChanged) {
-                    r.task.stack.releaseBackgroundResources();
+                    r.task.stack.releaseBackgroundResources(r);
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                 }
                 mWindowManager.setAppFullscreen(token, true);
@@ -10063,7 +10132,7 @@
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(false);
                 if (translucentChanged) {
-                    r.task.stack.convertToTranslucent(r);
+                    r.task.stack.convertActivityToTranslucent(r);
                 }
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                 mWindowManager.setAppFullscreen(token, false);
@@ -10580,9 +10649,68 @@
         }
     }
 
+    final class PreBootContinuation extends IIntentReceiver.Stub {
+        final Intent intent;
+        final Runnable onFinishCallback;
+        final ArrayList<ComponentName> doneReceivers;
+        final List<ResolveInfo> ris;
+        final int[] users;
+        int lastRi = -1;
+        int curRi = 0;
+        int curUser = 0;
+
+        PreBootContinuation(Intent _intent, Runnable _onFinishCallback,
+                ArrayList<ComponentName> _doneReceivers, List<ResolveInfo> _ris, int[] _users) {
+            intent = _intent;
+            onFinishCallback = _onFinishCallback;
+            doneReceivers = _doneReceivers;
+            ris = _ris;
+            users = _users;
+        }
+
+        void go() {
+            if (lastRi != curRi) {
+                ActivityInfo ai = ris.get(curRi).activityInfo;
+                ComponentName comp = new ComponentName(ai.packageName, ai.name);
+                intent.setComponent(comp);
+                doneReceivers.add(comp);
+                lastRi = curRi;
+                CharSequence label = ai.loadLabel(mContext.getPackageManager());
+                showBootMessage(mContext.getString(R.string.android_preparing_apk, label), false);
+            }
+            Slog.i(TAG, "Pre-boot of " + intent.getComponent().toShortString()
+                    + " for user " + users[curUser]);
+            EventLogTags.writeAmPreBoot(users[curUser], intent.getComponent().getPackageName());
+            broadcastIntentLocked(null, null, intent, null, this,
+                    0, null, null, null, AppOpsManager.OP_NONE,
+                    true, false, MY_PID, Process.SYSTEM_UID,
+                    users[curUser]);
+        }
+
+        public void performReceive(Intent intent, int resultCode,
+                String data, Bundle extras, boolean ordered,
+                boolean sticky, int sendingUser) {
+            curUser++;
+            if (curUser >= users.length) {
+                curUser = 0;
+                curRi++;
+                if (curRi >= ris.size()) {
+                    // All done sending broadcasts!
+                    if (onFinishCallback != null) {
+                        // The raw IIntentReceiver interface is called
+                        // with the AM lock held, so redispatch to
+                        // execute our code without the lock.
+                        mHandler.post(onFinishCallback);
+                    }
+                    return;
+                }
+            }
+            go();
+        }
+    }
+
     private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
             ArrayList<ComponentName> doneReceivers, int userId) {
-        boolean waitingUpdate = false;
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         List<ResolveInfo> ris = null;
         try {
@@ -10590,71 +10718,51 @@
                     intent, null, 0, userId);
         } catch (RemoteException e) {
         }
-        if (ris != null) {
-            for (int i=ris.size()-1; i>=0; i--) {
-                if ((ris.get(i).activityInfo.applicationInfo.flags
-                        &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                    ris.remove(i);
-                }
+        if (ris == null) {
+            return false;
+        }
+        for (int i=ris.size()-1; i>=0; i--) {
+            if ((ris.get(i).activityInfo.applicationInfo.flags
+                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
+                ris.remove(i);
             }
-            intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+        }
+        intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
 
-            // For User 0, load the version number. When delivering to a new user, deliver
-            // to all receivers.
-            if (userId == UserHandle.USER_OWNER) {
-                ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-                for (int i=0; i<ris.size(); i++) {
-                    ActivityInfo ai = ris.get(i).activityInfo;
-                    ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                    if (lastDoneReceivers.contains(comp)) {
-                        // We already did the pre boot receiver for this app with the current
-                        // platform version, so don't do it again...
-                        ris.remove(i);
-                        i--;
-                        // ...however, do keep it as one that has been done, so we don't
-                        // forget about it when rewriting the file of last done receivers.
-                        doneReceivers.add(comp);
-                    }
-                }
-            }
-
-            // If primary user, send broadcast to all available users, else just to userId
-            final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
-                    : new int[] { userId };
-            for (int i = 0; i < ris.size(); i++) {
+        // For User 0, load the version number. When delivering to a new user, deliver
+        // to all receivers.
+        if (userId == UserHandle.USER_OWNER) {
+            ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+            for (int i=0; i<ris.size(); i++) {
                 ActivityInfo ai = ris.get(i).activityInfo;
                 ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                doneReceivers.add(comp);
-                intent.setComponent(comp);
-                for (int j=0; j<users.length; j++) {
-                    IIntentReceiver finisher = null;
-                    // On last receiver and user, set up a completion callback
-                    if (i == ris.size() - 1 && j == users.length - 1 && onFinishCallback != null) {
-                        finisher = new IIntentReceiver.Stub() {
-                            public void performReceive(Intent intent, int resultCode,
-                                    String data, Bundle extras, boolean ordered,
-                                    boolean sticky, int sendingUser) {
-                                // The raw IIntentReceiver interface is called
-                                // with the AM lock held, so redispatch to
-                                // execute our code without the lock.
-                                mHandler.post(onFinishCallback);
-                            }
-                        };
-                    }
-                    Slog.i(TAG, "Sending system update to " + intent.getComponent()
-                            + " for user " + users[j]);
-                    broadcastIntentLocked(null, null, intent, null, finisher,
-                            0, null, null, null, AppOpsManager.OP_NONE,
-                            true, false, MY_PID, Process.SYSTEM_UID,
-                            users[j]);
-                    if (finisher != null) {
-                        waitingUpdate = true;
-                    }
+                if (false && lastDoneReceivers.contains(comp)) {
+                    // We already did the pre boot receiver for this app with the current
+                    // platform version, so don't do it again...
+                    ris.remove(i);
+                    i--;
+                    // ...however, do keep it as one that has been done, so we don't
+                    // forget about it when rewriting the file of last done receivers.
+                    doneReceivers.add(comp);
                 }
             }
         }
 
-        return waitingUpdate;
+        if (ris.size() <= 0) {
+            return false;
+        }
+
+        // If primary user, send broadcast to all available users, else just to userId
+        final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
+                : new int[] { userId };
+        if (users.length <= 0) {
+            return false;
+        }
+
+        PreBootContinuation cont = new PreBootContinuation(intent, onFinishCallback, doneReceivers,
+                ris, users);
+        cont.go();
+        return true;
     }
 
     public void systemReady(final Runnable goingCallback) {
@@ -10689,10 +10797,10 @@
                         synchronized (ActivityManagerService.this) {
                             mDidUpdate = true;
                         }
-                        writeLastDonePreBootReceivers(doneReceivers);
                         showBootMessage(mContext.getText(
                                 R.string.android_upgrading_complete),
                                 false);
+                        writeLastDonePreBootReceivers(doneReceivers);
                         systemReady(goingCallback);
                     }
                 }, doneReceivers, UserHandle.USER_OWNER);
@@ -10719,7 +10827,7 @@
                 }
             }
         }
-        
+
         synchronized(this) {
             if (procsToKill != null) {
                 for (int i=procsToKill.size()-1; i>=0; i--) {
@@ -10728,20 +10836,20 @@
                     removeProcessLocked(proc, true, false, "system update done");
                 }
             }
-            
+
             // Now that we have cleaned up any update processes, we
             // are ready to start launching real processes and know that
             // we won't trample on them any more.
             mProcessesReady = true;
         }
-        
+
         Slog.i(TAG, "System now ready");
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
             SystemClock.uptimeMillis());
 
         synchronized(this) {
             // Make sure we have no pre-ready processes sitting around.
-            
+
             if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 ResolveInfo ri = mContext.getPackageManager()
                         .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
@@ -10825,7 +10933,7 @@
             } catch (RemoteException e) {
             }
 
-            if (!Build.isFingerprintConsistent()) {
+            if (!Build.isBuildConsistent()) {
                 Slog.e(TAG, "Build fingerprint is not consistent, warning user");
                 mHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
             }
@@ -10881,12 +10989,12 @@
         startAppProblemLocked(app);
         app.stopFreezingAllLocked();
     }
-    
+
     /**
      * Generate a process error record, suitable for attachment to a ProcessRecord.
-     * 
+     *
      * @param app The ProcessRecord in which the error occurred.
-     * @param condition Crashing, Application Not Responding, etc.  Values are defined in 
+     * @param condition Crashing, Application Not Responding, etc.  Values are defined in
      *                      ActivityManager.AppErrorStateInfo
      * @param activity The activity associated with the crash, if known.
      * @param shortMsg Short message describing the crash.
@@ -10895,7 +11003,7 @@
      *
      * @return Returns a fully-formed AppErrorStateInfo record.
      */
-    private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app, 
+    private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
             int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
         ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
 
@@ -12307,12 +12415,12 @@
                 }
             }
         }
-        
+
         if (mForegroundProcesses.size() > 0) {
             synchronized (mPidsSelfLocked) {
                 boolean printed = false;
                 for (int i=0; i<mForegroundProcesses.size(); i++) {
-                    ProcessRecord r = mPidsSelfLocked.get( 
+                    ProcessRecord r = mPidsSelfLocked.get(
                             mForegroundProcesses.valueAt(i).pid);
                     if (dumpPackage != null && (r == null
                             || !r.pkgList.containsKey(dumpPackage))) {
@@ -12330,7 +12438,7 @@
                 }
             }
         }
-        
+
         if (mPersistentStartingProcesses.size() > 0) {
             if (needSep) pw.println();
             needSep = true;
@@ -12348,7 +12456,7 @@
             dumpProcessList(pw, this, mRemovedProcesses, "    ",
                     "Removed Norm", "Removed PERS", dumpPackage);
         }
-        
+
         if (mProcessesOnHold.size() > 0) {
             if (needSep) pw.println();
             needSep = true;
@@ -12359,7 +12467,7 @@
         }
 
         needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
-        
+
         if (mProcessCrashTimes.getMap().size() > 0) {
             boolean printed = false;
             long now = SystemClock.uptimeMillis();
@@ -12731,7 +12839,7 @@
         ArrayList<String> strings;
         ArrayList<Integer> objects;
         boolean all;
-        
+
         ItemMatcher() {
             all = true;
         }
@@ -12816,7 +12924,7 @@
     protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
         ArrayList<ActivityRecord> activities;
-        
+
         synchronized (this) {
             activities = mStackSupervisor.getDumpActivitiesLocked(name);
         }
@@ -12939,7 +13047,7 @@
         }
 
         needSep = true;
-        
+
         if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
             for (int user=0; user<mStickyBroadcasts.size(); user++) {
                 if (needSep) {
@@ -12974,7 +13082,7 @@
                 }
             }
         }
-        
+
         if (!onlyHistory && dumpAll) {
             pw.println();
             for (BroadcastQueue queue : mBroadcastQueues) {
@@ -12986,7 +13094,7 @@
             needSep = true;
             printedAnything = true;
         }
-        
+
         if (!printedAnything) {
             pw.println("  (nothing)");
         }
@@ -13326,7 +13434,7 @@
         long realtime = SystemClock.elapsedRealtime();
         pw.println("Applications Graphics Acceleration Info:");
         pw.println("Uptime: " + uptime + " Realtime: " + realtime);
-        
+
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = procs.get(i);
             if (r.thread != null) {
@@ -13551,7 +13659,7 @@
         boolean isCompact = false;
         boolean localOnly = false;
         boolean packages = false;
-        
+
         int opti = 0;
         while (opti < args.length) {
             String opt = args[opti];
@@ -13589,7 +13697,7 @@
                 pw.println("Unknown argument: " + opt + "; use -h for help");
             }
         }
-        
+
         final boolean isCheckinRequest = scanArgs(args, "--checkin");
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
@@ -13860,9 +13968,14 @@
             memInfo.readMemInfo();
             if (nativeProcTotalPss > 0) {
                 synchronized (this) {
-                    mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
-                            memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
-                            memInfo.getKernelUsedSizeKb(), nativeProcTotalPss);
+                    final long cachedKb = memInfo.getCachedSizeKb();
+                    final long freeKb = memInfo.getFreeSizeKb();
+                    final long zramKb = memInfo.getZramTotalSizeKb();
+                    final long kernelKb = memInfo.getKernelUsedSizeKb();
+                    EventLogTags.writeAmMeminfo(cachedKb*1024, freeKb*1024, zramKb*1024,
+                            kernelKb*1024, nativeProcTotalPss*1024);
+                    mProcessStats.addSysMemUsageLocked(cachedKb, freeKb, zramKb, kernelKb,
+                            nativeProcTotalPss);
                 }
             }
             if (!brief) {
@@ -14538,7 +14651,7 @@
         }
         return restart;
     }
-    
+
     // =========================================================
     // SERVICES
     // =========================================================
@@ -14620,7 +14733,7 @@
             return mServices.peekServiceLocked(service, resolvedType);
         }
     }
-    
+
     @Override
     public boolean stopServiceToken(ComponentName className, IBinder token,
             int startId) {
@@ -14843,11 +14956,11 @@
             mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
         }
     }
-    
+
     // =========================================================
     // BACKUP AND RESTORE
     // =========================================================
-    
+
     // Cause the target app to be launched if necessary and its backup agent
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
@@ -14910,7 +15023,7 @@
             // mBackupAppName describe the app, so that when it binds back to the AM we
             // know that it's scheduled for a backup-agent operation.
         }
-        
+
         return true;
     }
 
@@ -14996,30 +15109,6 @@
     // BROADCASTS
     // =========================================================
 
-    private final List getStickiesLocked(String action, IntentFilter filter,
-            List cur, int userId) {
-        final ContentResolver resolver = mContext.getContentResolver();
-        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
-        if (stickies == null) {
-            return cur;
-        }
-        final ArrayList<Intent> list = stickies.get(action);
-        if (list == null) {
-            return cur;
-        }
-        int N = list.size();
-        for (int i=0; i<N; i++) {
-            Intent intent = list.get(i);
-            if (filter.match(resolver, intent, true, TAG) >= 0) {
-                if (cur == null) {
-                    cur = new ArrayList<Intent>();
-                }
-                cur.add(intent);
-            }
-        }
-        return cur;
-    }
-
     boolean isPendingBroadcastProcessLocked(int pid) {
         return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
                 || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
@@ -15044,10 +15133,11 @@
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
             IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
         enforceNotIsolatedCaller("registerReceiver");
+        ArrayList<Intent> stickyIntents = null;
+        ProcessRecord callerApp = null;
         int callingUid;
         int callingPid;
         synchronized(this) {
-            ProcessRecord callerApp = null;
             if (caller != null) {
                 callerApp = getRecordForAppLocked(caller);
                 if (callerApp == null) {
@@ -15070,39 +15160,66 @@
                 callingPid = Binder.getCallingPid();
             }
 
-            userId = this.handleIncomingUser(callingPid, callingUid, userId,
+            userId = handleIncomingUser(callingPid, callingUid, userId,
                     true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
 
-            List allSticky = null;
+            Iterator<String> actions = filter.actionsIterator();
+            if (actions == null) {
+                ArrayList<String> noAction = new ArrayList<String>(1);
+                noAction.add(null);
+                actions = noAction.iterator();
+            }
 
-            // Look for any matching sticky broadcasts...
-            Iterator actions = filter.actionsIterator();
-            if (actions != null) {
-                while (actions.hasNext()) {
-                    String action = (String)actions.next();
-                    allSticky = getStickiesLocked(action, filter, allSticky,
-                            UserHandle.USER_ALL);
-                    allSticky = getStickiesLocked(action, filter, allSticky,
-                            UserHandle.getUserId(callingUid));
+            // Collect stickies of users
+            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
+            while (actions.hasNext()) {
+                String action = actions.next();
+                for (int id : userIds) {
+                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
+                    if (stickies != null) {
+                        ArrayList<Intent> intents = stickies.get(action);
+                        if (intents != null) {
+                            if (stickyIntents == null) {
+                                stickyIntents = new ArrayList<Intent>();
+                            }
+                            stickyIntents.addAll(intents);
+                        }
+                    }
                 }
-            } else {
-                allSticky = getStickiesLocked(null, filter, allSticky,
-                        UserHandle.USER_ALL);
-                allSticky = getStickiesLocked(null, filter, allSticky,
-                        UserHandle.getUserId(callingUid));
             }
+        }
 
-            // The first sticky in the list is returned directly back to
-            // the client.
-            Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
-
-            if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
-                    + ": " + sticky);
-
-            if (receiver == null) {
-                return sticky;
+        ArrayList<Intent> allSticky = null;
+        if (stickyIntents != null) {
+            final ContentResolver resolver = mContext.getContentResolver();
+            // Look for any matching sticky broadcasts...
+            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
+                Intent intent = stickyIntents.get(i);
+                // If intent has scheme "content", it will need to acccess
+                // provider that needs to lock mProviderMap in ActivityThread
+                // and also it may need to wait application response, so we
+                // cannot lock ActivityManagerService here.
+                if (filter.match(resolver, intent, true, TAG) >= 0) {
+                    if (allSticky == null) {
+                        allSticky = new ArrayList<Intent>();
+                    }
+                    allSticky.add(intent);
+                }
             }
+        }
 
+        // The first sticky in the list is returned directly back to the client.
+        Intent sticky = allSticky != null ? allSticky.get(0) : null;
+        if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter + ": " + sticky);
+        if (receiver == null) {
+            return sticky;
+        }
+
+        synchronized (this) {
+            if (callerApp != null && callerApp.pid == 0) {
+                // Caller already died
+                return null;
+            }
             ReceiverList rl
                 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
             if (rl == null) {
@@ -15213,7 +15330,7 @@
             mReceiverResolver.removeFilter(rl.get(i));
         }
     }
-    
+
     private final void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
         for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = mLruProcesses.get(i);
@@ -15637,10 +15754,10 @@
 
         final boolean replacePending =
                 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
-        
+
         if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
                 + " replacePending=" + replacePending);
-        
+
         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
         if (!ordered && NR > 0) {
             // If we are not serializing this broadcast, then send the
@@ -15741,14 +15858,14 @@
                     callerPackage, callingPid, callingUid, resolvedType,
                     requiredPermission, appOp, receivers, resultTo, resultCode,
                     resultData, map, ordered, sticky, false, userId);
+
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing ordered broadcast " + r
                     + ": prev had " + queue.mOrderedBroadcasts.size());
-            if (DEBUG_BROADCAST) {
-                int seq = r.intent.getIntExtra("seq", -1);
-                Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
-            }
-            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); 
+            if (DEBUG_BROADCAST) Slog.i(
+                    TAG, "Enqueueing broadcast " + r.intent.getAction());
+
+            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
             if (!replaced) {
                 queue.enqueueOrderedBroadcastLocked(r);
                 queue.scheduleBroadcastsLocked();
@@ -15905,7 +16022,7 @@
             Binder.restoreCallingIdentity(origId);
         }
     }
-    
+
     // =========================================================
     // INSTRUMENTATION
     // =========================================================
@@ -15975,17 +16092,17 @@
 
         return true;
     }
-    
+
     /**
-     * Report errors that occur while attempting to start Instrumentation.  Always writes the 
+     * Report errors that occur while attempting to start Instrumentation.  Always writes the
      * error to the logs, but if somebody is watching, send the report there too.  This enables
      * the "am" command to report errors with more information.
-     * 
+     *
      * @param watcher The IInstrumentationWatcher.  Null if there isn't one.
      * @param cn The component name of the instrumentation.
      * @param report The error report.
      */
-    private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher, 
+    private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
             ComponentName cn, String report) {
         Slog.w(TAG, report);
         try {
@@ -16055,7 +16172,7 @@
     // =========================================================
     // CONFIGURATION
     // =========================================================
-    
+
     public ConfigurationInfo getDeviceConfigurationInfo() {
         ConfigurationInfo config = new ConfigurationInfo();
         synchronized (this) {
@@ -16079,6 +16196,15 @@
         return mStackSupervisor.getFocusedStack();
     }
 
+    @Override
+    public int getFocusedStackId() throws RemoteException {
+        ActivityStack focusedStack = getFocusedStack();
+        if (focusedStack != null) {
+            return focusedStack.getStackId();
+        }
+        return -1;
+    }
+
     public Configuration getConfiguration() {
         Configuration ci;
         synchronized(this) {
@@ -16146,11 +16272,11 @@
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
                     Slog.i(TAG, "Updating configuration to: " + values);
                 }
-                
+
                 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
 
                 if (values.locale != null && !initLocale) {
-                    saveLocaleLocked(values.locale, 
+                    saveLocaleLocked(values.locale,
                                      !values.locale.equals(mConfiguration.locale),
                                      values.userSetLocale);
                 }
@@ -16166,7 +16292,7 @@
                 //mUsageStatsService.noteStartConfig(newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
-                
+
                 // TODO: If our config changes, should we auto dismiss any currently
                 // showing dialogs?
                 mShowDialogs = shouldShowDialogs(newConfig);
@@ -16255,7 +16381,8 @@
      */
     private static final boolean shouldShowDialogs(Configuration config) {
         return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
-                && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH);
+                && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
+                && config.navigation == Configuration.NAVIGATION_NONAV);
     }
 
     /**
@@ -16275,15 +16402,6 @@
 
         if (isPersist) {
             SystemProperties.set("persist.sys.locale", languageTag);
-
-            // These values are *deprecated*, use persist.sys.locale instead.
-            //
-            // TODO: Stop setting these values once all code that references
-            // them has been removed.
-            SystemProperties.set("persist.sys.language", l.getLanguage());
-            SystemProperties.set("persist.sys.country", l.getCountry());
-            SystemProperties.set("persist.sys.localevar", l.getVariant());
-
             mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG, l));
         }
     }
@@ -17029,7 +17147,7 @@
         }
 
         app.curRawAdj = adj;
-        
+
         //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
         //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
         if (adj > app.maxAdj) {
@@ -17056,6 +17174,7 @@
      * Record new PSS sample for a process.
      */
     void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) {
+        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
         if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
@@ -17141,7 +17260,7 @@
             // whatever.
         }
     }
-    
+
     /**
      * Returns true if things are idle enough to perform GCs.
      */
@@ -17155,7 +17274,7 @@
         return !processingBroadcasts
                 && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
     }
-    
+
     /**
      * Perform GCs on all processes that are waiting for it, but only
      * if things are idle.
@@ -17184,11 +17303,11 @@
                     }
                 }
             }
-            
+
             scheduleAppGcsLocked();
         }
     }
-    
+
     /**
      * If all looks good, perform GCs on all processes waiting for them.
      */
@@ -17206,12 +17325,12 @@
      */
     final void scheduleAppGcsLocked() {
         mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
-        
+
         if (mProcessesToGc.size() > 0) {
             // Schedule a GC for the time to the next process.
             ProcessRecord proc = mProcessesToGc.get(0);
             Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
-            
+
             long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
             long now = SystemClock.uptimeMillis();
             if (when < (now+GC_TIMEOUT)) {
@@ -17220,7 +17339,7 @@
             mHandler.sendMessageAtTime(msg, when);
         }
     }
-    
+
     /**
      * Add a process to the array of processes waiting to be GCed.  Keeps the
      * list in sorted order by the last GC time.  The process can't already be
@@ -17240,7 +17359,7 @@
             mProcessesToGc.add(0, proc);
         }
     }
-    
+
     /**
      * Set up to ask a process to GC itself.  This will either do it
      * immediately, or put it on the list of processes to gc the next
@@ -18309,8 +18428,8 @@
         }
     }
 
-    private Set getProfileIdsLocked(int userId) {
-        Set userIds = new HashSet<Integer>();
+    private Set<Integer> getProfileIdsLocked(int userId) {
+        Set<Integer> userIds = new HashSet<Integer>();
         final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
                 userId, false /* enabledOnly */);
         for (UserInfo user : profiles) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index a3676f9..b3f47e9 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -75,7 +75,6 @@
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
     final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
 
-    private static final String TAG_ACTIVITY = "activity";
     private static final String ATTR_ID = "id";
     private static final String TAG_INTENT = "intent";
     private static final String ATTR_USERID = "user_id";
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index dbd787b..4d7305d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -220,6 +220,9 @@
      */
     boolean mConfigWillChange;
 
+    // Whether or not this stack covers the entire screen; by default stacks are full screen
+    boolean mFullscreen = true;
+
     long mLaunchStartTime = 0;
     long mFullyDrawnStartTime = 0;
 
@@ -236,6 +239,9 @@
     final ActivityStackSupervisor mStackSupervisor;
 
     Configuration mOverrideConfig;
+    /** True if the stack was forced to full screen because {@link TaskRecord#mResizeable} is false
+     * and the stack was previously resized. */
+    private boolean mForcedFullscreen = false;
 
     static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
     static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
@@ -1125,7 +1131,8 @@
 
         final int numStacks = mStacks.size();
         while (stackNdx < numStacks) {
-            tasks = mStacks.get(stackNdx).mTaskHistory;
+            ActivityStack historyStack = mStacks.get(stackNdx);
+            tasks = historyStack.mTaskHistory;
             final int numTasks = tasks.size();
             while (taskNdx < numTasks) {
                 activities = tasks.get(taskNdx).mActivities;
@@ -1133,7 +1140,7 @@
                 while (activityNdx < numActivities) {
                     final ActivityRecord activity = activities.get(activityNdx);
                     if (!activity.finishing) {
-                        return activity.fullscreen ? null : activity;
+                        return historyStack.mFullscreen && activity.fullscreen ? null : activity;
                     }
                     ++activityNdx;
                 }
@@ -1149,7 +1156,7 @@
 
     // Checks if any of the stacks above this one has a fullscreen activity behind it.
     // If so, this stack is hidden, otherwise it is visible.
-    private boolean isStackVisible() {
+    private boolean isStackVisibleLocked() {
         if (!isAttached()) {
             return false;
         }
@@ -1164,11 +1171,18 @@
          * wallpaper to be shown behind it.
          */
         for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
-            final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
-            for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
+            ActivityStack stack = mStacks.get(i);
+            // stack above isn't full screen, so, we assume we're still visible. at some point
+            // we should look at the stack bounds to see if we're occluded even if the stack
+            // isn't fullscreen
+            if (!stack.mFullscreen) {
+                continue;
+            }
+            final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final TaskRecord task = tasks.get(taskNdx);
                 final ArrayList<ActivityRecord> activities = task.mActivities;
-                for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
+                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                     final ActivityRecord r = activities.get(activityNdx);
 
                     // Conditions for an activity to obscure the stack we're
@@ -1214,7 +1228,7 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         boolean aboveTop = true;
-        boolean behindFullscreen = !isStackVisible();
+        boolean behindFullscreen = !isStackVisibleLocked();
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1337,7 +1351,7 @@
                                     // This case created for transitioning activities from
                                     // translucent to opaque {@link Activity#convertToOpaque}.
                                     if (getVisibleBehindActivity() == r) {
-                                        releaseBackgroundResources();
+                                        releaseBackgroundResources(r);
                                     } else {
                                         if (!mStackSupervisor.mStoppingActivities.contains(r)) {
                                             mStackSupervisor.mStoppingActivities.add(r);
@@ -1369,7 +1383,7 @@
         }
     }
 
-    void convertToTranslucent(ActivityRecord r) {
+    void convertActivityToTranslucent(ActivityRecord r) {
         mTranslucentActivityWaiting = r;
         mUndrawnActivitiesBelowTopTranslucent.clear();
         mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
@@ -1905,9 +1919,31 @@
         return true;
     }
 
+    private TaskRecord getNextTask(TaskRecord targetTask) {
+        final int index = mTaskHistory.indexOf(targetTask);
+        if (index >= 0) {
+            final int numTasks = mTaskHistory.size();
+            for (int i = index + 1; i < numTasks; ++i) {
+                TaskRecord task = mTaskHistory.get(i);
+                if (task.userId == targetTask.userId) {
+                    return task;
+                }
+            }
+        }
+        return null;
+    }
+
     private void insertTaskAtTop(TaskRecord task) {
+        // If the moving task is over home stack, transfer its return type to next task
+        if (task.isOverHomeStack()) {
+            final TaskRecord nextTask = getNextTask(task);
+            if (nextTask != null) {
+                nextTask.setTaskToReturnTo(task.getTaskToReturnTo());
+            }
+        }
+
         // If this is being moved to the top by another activity or being launched from the home
-        // activity, set mOnTopOfHome accordingly.
+        // activity, set mTaskToReturnTo accordingly.
         if (isOnHomeDisplay()) {
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHome = lastStack.isHomeStack();
@@ -3282,10 +3318,9 @@
         }
     }
 
-    void releaseBackgroundResources() {
+    void releaseBackgroundResources(ActivityRecord r) {
         if (hasVisibleBehindActivity() &&
                 !mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
-            final ActivityRecord r = getVisibleBehindActivity();
             if (r == topRunningActivityLocked(null)) {
                 // Don't release the top activity if it has requested to run behind the next
                 // activity.
@@ -3567,6 +3602,15 @@
         if (DEBUG_TRANSITION) Slog.v(TAG,
                 "Prepare to back transition: task=" + taskId);
 
+        boolean prevIsHome = false;
+        if (tr.isOverHomeStack()) {
+            final TaskRecord nextTask = getNextTask(tr);
+            if (nextTask != null) {
+                nextTask.setTaskToReturnTo(tr.getTaskToReturnTo());
+            } else {
+                prevIsHome = true;
+            }
+        }
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
         updateTaskMovement(tr, false);
@@ -3593,7 +3637,8 @@
         }
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
-        if (task == tr && tr.isOverHomeStack() || numTasks <= 1 && isOnHomeDisplay()) {
+        if (prevIsHome || task == tr && tr.isOverHomeStack()
+                || numTasks <= 1 && isOnHomeDisplay()) {
             if (!mService.mBooting && !mService.mBooted) {
                 // Not ready yet!
                 return false;
@@ -3636,6 +3681,24 @@
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                 "Ensuring correct configuration: " + r);
 
+        // Make sure the current stack override configuration is supported by the top task
+        // before continuing.
+        final TaskRecord topTask = topTask();
+        if (topTask != null && ((topTask.mResizeable && mForcedFullscreen)
+                    || (!topTask.mResizeable && !mFullscreen))) {
+            final boolean prevFullscreen = mFullscreen;
+            final Configuration newOverrideConfig =
+                    mWindowManager.forceStackToFullscreen(mStackId, !topTask.mResizeable);
+            updateOverrideConfiguration(newOverrideConfig);
+            mForcedFullscreen = !prevFullscreen && mFullscreen;
+            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+                    "Updated stack config to support task=" + topTask
+                            + " resizeable=" + topTask.mResizeable
+                            + " mForcedFullscreen=" + mForcedFullscreen
+                            + " prevFullscreen=" + prevFullscreen
+                            + " mFullscreen=" + mFullscreen);
+        }
+
         // Short circuit: if the two configurations are the exact same
         // object (the common case), then there is nothing to do.
         Configuration newConfig = mService.mConfiguration;
@@ -3667,10 +3730,19 @@
         // we just want to leave the official config object now in the
         // activity and do nothing else.
         int stackChanges = oldStackOverride.diff(mOverrideConfig);
-        if (stackChanges == 0 && !oldStackOverride.equals(mOverrideConfig)) {
-            // Assume size change if diff didn't report any changes,
-            // but configurations are not equal.
-            stackChanges = ActivityInfo.CONFIG_SCREEN_SIZE;
+        if (stackChanges == 0) {
+            // {@link Configuration#diff} doesn't catch changes from unset values.
+            // Check for changes we care about.
+            if (oldStackOverride.orientation != mOverrideConfig.orientation) {
+                stackChanges |= ActivityInfo.CONFIG_ORIENTATION;
+            }
+            if (oldStackOverride.screenHeightDp != mOverrideConfig.screenHeightDp
+                    || oldStackOverride.screenWidthDp != mOverrideConfig.screenWidthDp) {
+                stackChanges |= ActivityInfo.CONFIG_SCREEN_SIZE;
+            }
+            if (oldStackOverride.smallestScreenWidthDp != mOverrideConfig.smallestScreenWidthDp) {
+                stackChanges |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+            }
         }
         final int changes = oldConfig.diff(newConfig) | stackChanges;
         if (changes == 0 && !r.forceNewConfig) {
@@ -3734,15 +3806,15 @@
             return false;
         }
 
-        // Default case: the activity can handle this new configuration, so
-        // hand it over.  Note that we don't need to give it the new
-        // configuration, since we always send configuration changes to all
-        // process when they happen so it can just use whatever configuration
-        // it last got.
+        // Default case: the activity can handle this new configuration, so hand it over.
+        // NOTE: We only forward the stack override configuration as the system level configuration
+        // changes is always sent to all processes when they happen so it can just use whatever
+        // system level configuration it last got.
         if (r.app != null && r.app.thread != null) {
             try {
                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
-                r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
+                r.app.thread.scheduleActivityConfigurationChanged(
+                        r.appToken, new Configuration(mOverrideConfig));
             } catch (RemoteException e) {
                 // If process died, whatever.
             }
@@ -4111,7 +4183,7 @@
     }
 
     ArrayList<TaskRecord> getAllTasks() {
-        return new ArrayList<TaskRecord>(mTaskHistory);
+        return new ArrayList<>(mTaskHistory);
     }
 
     void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
@@ -4143,6 +4215,10 @@
     boolean updateOverrideConfiguration(Configuration newConfig) {
         Configuration oldConfig = mOverrideConfig;
         mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
+        // We override the configuration only when the stack's dimensions are different from
+        // the display. In this manner, we know that if the override configuration is empty,
+        // the stack is necessarily full screen.
+        mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
         return !mOverrideConfig.equals(oldConfig);
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4674cc2..1aa2a10 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -882,7 +882,8 @@
             final long origId = Binder.clearCallingIdentity();
 
             if (aInfo != null &&
-                    (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+                    (aInfo.applicationInfo.privateFlags
+                            &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Check to see if we already
                 // have another, different heavy-weight process running.
                 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
@@ -1053,8 +1054,8 @@
                     aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
                     if (aInfo != null &&
-                            (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE)
-                                    != 0) {
+                            (aInfo.applicationInfo.privateFlags
+                                    & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)  != 0) {
                         throw new IllegalArgumentException(
                                 "FLAG_CANT_SAVE_STATE not supported here");
                     }
@@ -1185,7 +1186,7 @@
                     r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                     newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
 
-            if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+            if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Note that the package
                 // manager will ensure that only activity can run in the main
                 // process of the .apk, which is the only thing that will be
@@ -2604,9 +2605,15 @@
             Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
             return;
         }
+
+        final ActivityRecord r = stack.topRunningActivityLocked(null);
+        if (r != null && !r.task.mResizeable) {
+            Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable.");
+            return;
+        }
+
         final Configuration overrideConfig = mWindowManager.resizeStack(stackId, bounds);
         if (stack.updateOverrideConfiguration(overrideConfig)) {
-            final ActivityRecord r = stack.topRunningActivityLocked(null);
             if (r != null) {
                 final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
                 // And we need to make sure at this point that all other activities
@@ -3752,6 +3759,13 @@
         }
 
         @Override
+        public int getStackId() {
+            synchronized (mService) {
+                return mStackId;
+            }
+        }
+
+        @Override
         public boolean injectEvent(InputEvent event) {
             final long origId = Binder.clearCallingIdentity();
             try {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 9b7d0b2..7ab3794 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -513,11 +513,7 @@
                 }
             }
             try {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    int seq = r.intent.getIntExtra("seq", -1);
-                    Slog.i(TAG, "Delivering to " + filter
-                            + " (seq=" + seq + "): " + r);
-                }
+                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG, "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);
@@ -662,12 +658,9 @@
                     // result if requested...
                     if (r.resultTo != null) {
                         try {
-                            if (DEBUG_BROADCAST) {
-                                int seq = r.intent.getIntExtra("seq", -1);
-                                Slog.i(TAG, "Finishing broadcast ["
-                                        + mQueueName + "] " + r.intent.getAction()
-                                        + " seq=" + seq + " app=" + r.callerApp);
-                            }
+                            if (DEBUG_BROADCAST) Slog.i(TAG,
+                                    "Finishing broadcast [" + mQueueName + "] "
+                                    + r.intent.getAction() + " app=" + r.callerApp);
                             performReceiveLocked(r.callerApp, r.resultTo,
                                 new Intent(r.intent), r.resultCode,
                                 r.resultData, r.resultExtras, false, false, r.userId);
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index c376744..9a645df 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -95,3 +95,11 @@
 
 # Home Stack brought to front or rear
 30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3)
+
+# Running pre boot receiver
+30045 am_pre_boot (User|1|5),(Package|3)
+
+# Report collection of global memory state
+30046 am_meminfo (CachedKb|2|2),(FreeKb|2|2),(ZramKb|2|2),(KernelKb|2|2),(NativeKb|2|2)
+# Report collection of memory used by a process
+30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(PssKb|2|2),(UssKb|2|2)
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 3011148..76bb498 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -79,6 +79,7 @@
     private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
     private static final String ATTR_CALLING_UID = "calling_uid";
     private static final String ATTR_CALLING_PACKAGE = "calling_package";
+    private static final String ATTR_RESIZEABLE = "resizeable";
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
@@ -109,10 +110,12 @@
 
     String stringName;      // caching of toString() result.
     int userId;             // user for which this task was created
-    int creatorUid;         // The app uid that originally created the task
 
     int numFullscreen;      // Number of fullscreen activities.
 
+    boolean mResizeable;    // Activities in the task resizeable. Based on the resizable setting of
+                            // the root activity.
+
     // This represents the last resolved activity values for this task
     // NOTE: This value needs to be persisted with each task
     TaskDescription lastTaskDescription = new TaskDescription();
@@ -176,7 +179,7 @@
         voiceSession = _voiceSession;
         voiceInteractor = _voiceInteractor;
         isAvailable = true;
-        mActivities = new ArrayList<ActivityRecord>();
+        mActivities = new ArrayList<>();
         setIntent(_intent, info);
     }
 
@@ -191,7 +194,7 @@
         voiceSession = null;
         voiceInteractor = null;
         isAvailable = true;
-        mActivities = new ArrayList<ActivityRecord>();
+        mActivities = new ArrayList<>();
         setIntent(_intent, info);
 
         taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -210,15 +213,15 @@
         mCallingPackage = info.packageName;
     }
 
-    TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
-            String _affinity, String _rootAffinity, ComponentName _realActivity,
-            ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents,
-            boolean _askedCompatMode, int _taskType, int _userId, int _effectiveUid,
-            String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
-            long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
-            TaskDescription _lastTaskDescription, int taskAffiliation,
-            int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid,
-            String callingPackage) {
+    private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
+            Intent _affinityIntent, String _affinity, String _rootAffinity,
+            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
+            boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId,
+            int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
+            long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
+            boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
+            int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
+            int callingUid, String callingPackage, boolean resizeable) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -227,7 +230,7 @@
         intent = _intent;
         affinityIntent = _affinityIntent;
         affinity = _affinity;
-        rootAffinity = _affinity;
+        rootAffinity = _rootAffinity;
         voiceSession = null;
         voiceInteractor = null;
         realActivity = _realActivity;
@@ -253,6 +256,7 @@
         mNextAffiliateTaskId = nextTaskId;
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
+        mResizeable = resizeable;
     }
 
     void touchActiveTime() {
@@ -352,6 +356,7 @@
         } else {
             autoRemoveRecents = false;
         }
+        mResizeable = info.resizeable;
     }
 
     void setTaskToReturnTo(int taskToReturnTo) {
@@ -850,6 +855,7 @@
         out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
         out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
+        out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
 
         if (affinityIntent != null) {
             out.startTag(null, TAG_AFFINITYINTENT);
@@ -911,6 +917,7 @@
         int nextTaskId = INVALID_TASK_ID;
         int callingUid = -1;
         String callingPackage = "";
+        boolean resizeable = false;
 
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
@@ -964,6 +971,8 @@
                 callingUid = Integer.valueOf(attrValue);
             } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
                 callingPackage = attrValue;
+            } else if (ATTR_RESIZEABLE.equals(attrName)) {
+                resizeable = Boolean.valueOf(attrValue);
             } else {
                 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
             }
@@ -993,13 +1002,11 @@
                 }
             }
         }
-
         if (!hasRootAffinity) {
             rootAffinity = affinity;
         } else if ("@".equals(rootAffinity)) {
             rootAffinity = null;
         }
-
         if (effectiveUid <= 0) {
             Intent checkIntent = intent != null ? intent : affinityIntent;
             effectiveUid = 0;
@@ -1025,7 +1032,7 @@
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
-                callingUid, callingPackage);
+                callingUid, callingPackage, resizeable);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             activities.get(activityNdx).task = task;
@@ -1121,6 +1128,7 @@
             pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
         }
         pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
+                pw.print(" mResizeable="); pw.print(mResizeable);
                 pw.print(" firstActiveTime="); pw.print(lastActiveTime);
                 pw.print(" lastActiveTime="); pw.print(lastActiveTime);
                 pw.print(" (inactive for ");
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 36263ec..5a66f4a 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -19,6 +19,8 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -26,6 +28,7 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 
 /**
  * Dialog to show when a user switch it about to happen. The intent is to snapshot the screen
@@ -37,8 +40,14 @@
         implements ViewTreeObserver.OnWindowShownListener {
     private static final String TAG = "ActivityManagerUserSwitchingDialog";
 
+    // Time to wait for the onWindowShown() callback before continuing the user switch
+    private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000;
+
     private final ActivityManagerService mService;
     private final int mUserId;
+    private static final int MSG_START_USER = 1;
+    @GuardedBy("this")
+    private boolean mStartedUser;
 
     public UserSwitchingDialog(ActivityManagerService service, Context context,
             int userId, String userName, boolean aboveSystem) {
@@ -73,15 +82,40 @@
         if (decorView != null) {
             decorView.getViewTreeObserver().addOnWindowShownListener(this);
         }
+        // Add a timeout as a safeguard, in case a race in screen on/off causes the window
+        // callback to never come.
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER),
+                WINDOW_SHOWN_TIMEOUT_MS);
     }
 
     @Override
     public void onWindowShown() {
         // Slog.v(TAG, "onWindowShown called");
-        mService.startUserInForeground(mUserId, this);
-        final View decorView = getWindow().getDecorView();
-        if (decorView != null) {
-            decorView.getViewTreeObserver().removeOnWindowShownListener(this);
+        startUser();
+    }
+
+    void startUser() {
+        synchronized (this) {
+            if (!mStartedUser) {
+                mService.startUserInForeground(mUserId, this);
+                mStartedUser = true;
+                final View decorView = getWindow().getDecorView();
+                if (decorView != null) {
+                    decorView.getViewTreeObserver().removeOnWindowShownListener(this);
+                }
+                mHandler.removeMessages(MSG_START_USER);
+            }
         }
     }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START_USER:
+                    startUser();
+                    break;
+            }
+        }
+    };
 }
diff --git a/media/java/android/media/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
similarity index 93%
rename from media/java/android/media/AudioService.java
rename to services/core/java/com/android/server/audio/AudioService.java
index 0ffa5fc..eaece09 100644
--- a/media/java/android/media/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.server.audio;
 
 import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
 import static android.media.AudioManager.RINGER_MODE_NORMAL;
@@ -46,8 +46,30 @@
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.usb.UsbManager;
+import android.media.AudioAttributes;
+import android.media.AudioDevicePort;
+import android.media.AudioSystem;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioManagerInternal;
+import android.media.AudioPort;
+import android.media.AudioRoutesInfo;
+import android.media.AudioSystem;
+import android.media.IAudioFocusDispatcher;
+import android.media.IAudioRoutesObserver;
+import android.media.IAudioService;
+import android.media.IRemoteControlDisplay;
+import android.media.IRingtonePlayer;
+import android.media.IVolumeController;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import android.media.AudioAttributes.Builder;
+import android.media.AudioManagerInternal.RingerModeDelegate;
+import android.media.AudioSystem.ErrorCallback;
+import android.media.IAudioService.Stub;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
+import android.media.SoundPool.OnLoadCompleteListener;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
@@ -135,13 +157,8 @@
     /** How long to delay before persisting a change in volume/ringer mode. */
     private static final int PERSIST_DELAY = 500;
 
-    /**
-     * The delay before playing a sound. This small period exists so the user
-     * can press another key (non-volume keys, too) to have it NOT be audible.
-     * <p>
-     * PhoneWindow will implement this part.
-     */
-    public static final int PLAY_SOUND_DELAY = 300;
+    /** How long to delay after a volume down event before unmuting a stream */
+    private static final int UNMUTE_STREAM_DELAY = 350;
 
     /**
      * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
@@ -152,21 +169,15 @@
     private final ContentResolver mContentResolver;
     private final AppOpsManager mAppOps;
 
-    // the platform has no specific capabilities
-    private static final int PLATFORM_DEFAULT = 0;
-    // the platform is voice call capable (a phone)
-    private static final int PLATFORM_VOICE = 1;
-    // the platform is a television or a set-top box
-    private static final int PLATFORM_TELEVISION = 2;
     // the platform type affects volume and silent mode behavior
     private final int mPlatformType;
 
     private boolean isPlatformVoice() {
-        return mPlatformType == PLATFORM_VOICE;
+        return mPlatformType == AudioSystem.PLATFORM_VOICE;
     }
 
     private boolean isPlatformTelevision() {
-        return mPlatformType == PLATFORM_TELEVISION;
+        return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
     }
 
     /** The controller for the volume UI. */
@@ -205,6 +216,7 @@
     private static final int MSG_SYSTEM_READY = 21;
     private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
     private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
+    private static final int MSG_UNMUTE_STREAM = 24;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -263,19 +275,6 @@
         15  // STREAM_TTS
     };
 
-    private static int[] DEFAULT_STREAM_VOLUME = new int[] {
-        4,  // STREAM_VOICE_CALL
-        7,  // STREAM_SYSTEM
-        5,  // STREAM_RING
-        11, // STREAM_MUSIC
-        6,  // STREAM_ALARM
-        5,  // STREAM_NOTIFICATION
-        7,  // STREAM_BLUETOOTH_SCO
-        7,  // STREAM_SYSTEM_ENFORCED
-        11, // STREAM_DTMF
-        11  // STREAM_TTS
-    };
-
     /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
      * of another stream: This avoids multiplying the volume settings for hidden
      * stream types that follow other stream behavior for volume settings
@@ -342,20 +341,6 @@
 
     private final boolean mUseFixedVolume;
 
-    // stream names used by dumpStreamStates()
-    private static final String[] STREAM_NAMES = new String[] {
-            "STREAM_VOICE_CALL",
-            "STREAM_SYSTEM",
-            "STREAM_RING",
-            "STREAM_MUSIC",
-            "STREAM_ALARM",
-            "STREAM_NOTIFICATION",
-            "STREAM_BLUETOOTH_SCO",
-            "STREAM_SYSTEM_ENFORCED",
-            "STREAM_DTMF",
-            "STREAM_TTS"
-    };
-
     private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
         public void onError(int error) {
             switch (error) {
@@ -536,6 +521,20 @@
 
     private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
 
+    // Intent "extra" data keys.
+    public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
+    public static final String CONNECT_INTENT_KEY_STATE = "state";
+    public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
+    public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
+    public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
+    public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
+    public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
+
+    // Defines the format for the connection "address" for ALSA devices
+    public static String makeAlsaAddressString(int card, int device) {
+        return "card=" + card + ";device=" + device + ";";
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -546,15 +545,7 @@
         mContentResolver = context.getContentResolver();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
 
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable)) {
-            mPlatformType = PLATFORM_VOICE;
-        } else if (context.getPackageManager().hasSystemFeature(
-                                                            PackageManager.FEATURE_LEANBACK)) {
-            mPlatformType = PLATFORM_TELEVISION;
-        } else {
-            mPlatformType = PLATFORM_DEFAULT;
-        }
+        mPlatformType = AudioSystem.getPlatformType(context);
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -567,13 +558,13 @@
                 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
         if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
             MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
-            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
+            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
         }
         maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
                 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
         if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
             MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
-            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
+            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
         }
 
         sSoundEffectVolumeDb = context.getResources().getInteger(
@@ -748,7 +739,7 @@
                                     setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
                 }
                 // apply stream volume
-                if (!mStreamStates[streamType].isMuted_syncVSS()) {
+                if (!mStreamStates[streamType].mIsMuted) {
                     mStreamStates[streamType].applyAllVolumes();
                 }
             }
@@ -783,7 +774,7 @@
         pw.println("\nStream volumes (device: index)");
         int numStreamTypes = AudioSystem.getNumStreamTypes();
         for (int i = 0; i < numStreamTypes; i++) {
-            pw.println("- "+STREAM_NAMES[i]+":");
+            pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
             mStreamStates[i].dump(pw);
             pw.println("");
         }
@@ -791,22 +782,15 @@
         pw.println(Integer.toHexString(mMuteAffectedStreams));
     }
 
-    /** @hide */
-    public static String streamToString(int stream) {
-        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
-        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
-        return "UNKNOWN_STREAM_" + stream;
-    }
-
     private void updateStreamVolumeAlias(boolean updateVolumes) {
         int dtmfStreamAlias;
 
         switch (mPlatformType) {
-        case PLATFORM_VOICE:
+        case AudioSystem.PLATFORM_VOICE:
             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
             dtmfStreamAlias = AudioSystem.STREAM_RING;
             break;
-        case PLATFORM_TELEVISION:
+        case AudioSystem.PLATFORM_TELEVISION:
             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
             dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
             break;
@@ -885,11 +869,11 @@
             // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
             // are still needed while setVibrateSetting() and getVibrateSetting() are being
             // deprecated.
-            mVibrateSetting = getValueForVibrateSetting(0,
+            mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
                                             AudioManager.VIBRATE_TYPE_NOTIFICATION,
                                             mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
                                                             : AudioManager.VIBRATE_SETTING_OFF);
-            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
+            mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
                                             AudioManager.VIBRATE_TYPE_RINGER,
                                             mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
                                                             : AudioManager.VIBRATE_SETTING_OFF);
@@ -899,11 +883,8 @@
         }
 
         mMuteAffectedStreams = System.getIntForUser(cr,
-                System.MUTE_STREAMS_AFFECTED,
-                ((1 << AudioSystem.STREAM_MUSIC)|
-                 (1 << AudioSystem.STREAM_RING)|
-                 (1 << AudioSystem.STREAM_SYSTEM)),
-                 UserHandle.USER_CURRENT);
+                System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
+                UserHandle.USER_CURRENT);
 
         boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
                                                   0, UserHandle.USER_CURRENT) == 1;
@@ -970,6 +951,7 @@
         if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
                 + ", flags=" + flags);
         int streamType;
+        boolean isMute = isMuteAdjust(direction);
         if (mVolumeControlStream != -1) {
             streamType = mVolumeControlStream;
         } else {
@@ -984,7 +966,8 @@
         }
 
         // For notifications/ring, show the ui before making any adjustments
-        if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
+        // Don't suppress mute/unmute requests
+        if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
             direction = 0;
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
             flags &= ~AudioManager.FLAG_VIBRATE;
@@ -1011,10 +994,17 @@
         ensureValidDirection(direction);
         ensureValidStreamType(streamType);
 
+        boolean isMuteAdjust = isMuteAdjust(direction);
+
         // use stream type alias here so that streams with same alias have the same behavior,
         // including with regard to silent mode control (e.g the use of STREAM_RING below and in
         // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
         int streamTypeAlias = mStreamVolumeAlias[streamType];
+
+        if (isMuteAdjust && !isStreamAffectedByMute(streamTypeAlias)) {
+            return;
+        }
+
         VolumeStreamState streamState = mStreamStates[streamTypeAlias];
 
         final int device = getDeviceForStream(streamTypeAlias);
@@ -1071,9 +1061,9 @@
             if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
                 flags &= ~AudioManager.FLAG_VIBRATE;
             }
-            // Check if the ringer mode changes with this volume adjustment. If
-            // it does, it will handle adjusting the volume, so we won't below
-            final int result = checkForRingerModeChange(aliasIndex, direction, step);
+            // Check if the ringer mode handles this adjustment. If it does we don't
+            // need to adjust the volume further.
+            final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
             adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
             // If suppressing a volume adjustment in silent mode, display the UI hint
             if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
@@ -1088,6 +1078,7 @@
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
         if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+            mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
 
             // Check if volume update should be send to AVRCP
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
@@ -1100,13 +1091,43 @@
                 }
             }
 
-            if ((direction == AudioManager.ADJUST_RAISE) &&
+            if (isMuteAdjust) {
+                boolean state;
+                if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
+                    state = !streamState.mIsMuted;
+                } else {
+                    state = direction == AudioManager.ADJUST_MUTE;
+                }
+                if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
+                    setSystemAudioMute(state);
+                }
+                for (int stream = 0; stream < mStreamStates.length; stream++) {
+                    if (streamTypeAlias == mStreamVolumeAlias[stream]) {
+                        mStreamStates[stream].mute(state);
+
+                        Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+                        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
+                        intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
+                        sendBroadcastToAll(intent);
+                    }
+                }
+            } else if ((direction == AudioManager.ADJUST_RAISE) &&
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
-                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
+                Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
                 mVolumeController.postDisplaySafeVolumeWarning(flags);
-            } else if (streamState.adjustIndex(direction * step, device)) {
-                // Post message to set system volume (it in turn will post a message
-                // to persist). Do not change volume if stream is muted.
+            } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
+                // Post message to set system volume (it in turn will post a
+                // message to persist).
+                if (streamState.mIsMuted) {
+                    // Unmute the stream if it was previously muted
+                    if (direction == AudioManager.ADJUST_RAISE) {
+                        // unmute immediately for volume up
+                        streamState.mute(false);
+                    } else if (direction == AudioManager.ADJUST_LOWER) {
+                        sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
+                                streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
+                    }
+                }
                 sendMsg(mAudioHandler,
                         MSG_SET_DEVICE_VOLUME,
                         SENDMSG_QUEUE,
@@ -1116,7 +1137,7 @@
                         0);
             }
 
-            // Check if volume update should be send to Hdmi system audio.
+            // Check if volume update should be sent to Hdmi system audio.
             int newIndex = mStreamStates[streamType].getIndex(device);
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
@@ -1129,7 +1150,7 @@
                             oldIndex != newIndex) {
                         synchronized (mHdmiPlaybackClient) {
                             int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
-                                                               KeyEvent.KEYCODE_VOLUME_UP;
+                                    KeyEvent.KEYCODE_VOLUME_UP;
                             mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
                             mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
                         }
@@ -1141,6 +1162,16 @@
         sendVolumeUpdate(streamType, oldIndex, index, flags);
     }
 
+    // Called after a delay when volume down is pressed while muted
+    private void onUnmuteStream(int stream, int flags) {
+        VolumeStreamState streamState = mStreamStates[stream];
+        streamState.mute(false);
+
+        final int device = getDeviceForStream(stream);
+        final int index = mStreamStates[stream].getIndex(device);
+        sendVolumeUpdate(stream, index, index, flags);
+    }
+
     private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
         if (mHdmiManager == null
                 || mHdmiTvClient == null
@@ -1172,6 +1203,10 @@
         if (mUseFixedVolume) {
             return;
         }
+        if (isMuteAdjust(steps)) {
+            setMasterMuteInternal(steps, flags, callingPackage, uid);
+            return;
+        }
         ensureValidSteps(steps);
         int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
         int delta = 0;
@@ -1500,46 +1535,6 @@
         }
     }
 
-    /** @see AudioManager#setStreamSolo(int, boolean) */
-    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        int streamAlias = mStreamVolumeAlias[streamType];
-        for (int stream = 0; stream < mStreamStates.length; stream++) {
-            if (!isStreamAffectedByMute(streamAlias) || streamAlias == mStreamVolumeAlias[stream]) {
-                continue;
-            }
-            mStreamStates[stream].mute(cb, state);
-         }
-    }
-
-    /** @see AudioManager#setStreamMute(int, boolean) */
-    public void setStreamMute(int streamType, boolean state, IBinder cb) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-            streamType = getActiveStreamType(streamType);
-        }
-        int streamAlias = mStreamVolumeAlias[streamType];
-        if (isStreamAffectedByMute(streamAlias)) {
-            if (streamAlias == AudioSystem.STREAM_MUSIC) {
-                setSystemAudioMute(state);
-            }
-            for (int stream = 0; stream < mStreamStates.length; stream++) {
-                if (streamAlias == mStreamVolumeAlias[stream]) {
-                    mStreamStates[stream].mute(cb, state);
-
-                    Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
-                    intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
-                    intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
-                    sendBroadcastToAll(intent);
-                }
-            }
-        }
-    }
-
     private void setSystemAudioMute(boolean state) {
         if (mHdmiManager == null || mHdmiTvClient == null) return;
         synchronized (mHdmiManager) {
@@ -1561,7 +1556,7 @@
             streamType = getActiveStreamType(streamType);
         }
         synchronized (VolumeStreamState.class) {
-            return mStreamStates[streamType].isMuted_syncVSS();
+            return mStreamStates[streamType].mIsMuted;
         }
     }
 
@@ -1665,20 +1660,17 @@
         }
     }
 
-    /** @see AudioManager#setMasterMute(boolean, int) */
-    public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
-        setMasterMuteInternal(state, flags, callingPackage, cb, Binder.getCallingUid());
-    }
-
-    private void setMasterMuteInternal(boolean state, int flags, String callingPackage, IBinder cb,
-            int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
+    private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
         if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
                 != AppOpsManager.MODE_ALLOWED) {
             return;
         }
+        boolean state;
+        if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
+            state = !AudioSystem.getMasterMute();
+        } else {
+            state = adjust == AudioManager.ADJUST_MUTE;
+        }
         if (state != AudioSystem.getMasterMute()) {
             setSystemAudioMute(state);
             AudioSystem.setMasterMute(state);
@@ -1702,10 +1694,6 @@
         return MAX_STREAM_VOLUME[streamType];
     }
 
-    public static int getDefaultStreamVolume(int streamType) {
-        return DEFAULT_STREAM_VOLUME[streamType];
-    }
-
     /** @see AudioManager#getStreamVolume(int) */
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -1714,7 +1702,7 @@
             int index = mStreamStates[streamType].getIndex(device);
 
             // by convention getStreamVolume() returns 0 when a stream is muted.
-            if (mStreamStates[streamType].isMuted_syncVSS()) {
+            if (mStreamStates[streamType].mIsMuted) {
                 index = 0;
             }
             if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
@@ -1934,11 +1922,11 @@
                         }
                     }
                 }
-                mStreamStates[streamType].mute(null, false);
+                mStreamStates[streamType].mute(false);
                 mRingerModeMutedStreams &= ~(1 << streamType);
             } else {
                 // mute
-                mStreamStates[streamType].mute(null, true);
+                mStreamStates[streamType].mute(true);
                 mRingerModeMutedStreams |= (1 << streamType);
             }
         }
@@ -2000,29 +1988,14 @@
 
         if (!mHasVibrator) return;
 
-        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
+        mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
+                vibrateSetting);
 
         // Broadcast change
         broadcastVibrateSetting(vibrateType);
 
     }
 
-    /**
-     * @see #setVibrateSetting(int, int)
-     */
-    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
-            int vibrateSetting) {
-
-        // First clear the existing setting. Each vibrate type has two bits in
-        // the value. Note '3' is '11' in binary.
-        existingValue &= ~(3 << (vibrateType * 2));
-
-        // Set into the old value
-        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
-
-        return existingValue;
-    }
-
     private class SetModeDeathHandler implements IBinder.DeathRecipient {
         private IBinder mCb; // To be notified of client's death
         private int mPid;
@@ -2426,13 +2399,9 @@
             streamState.readSettings();
             synchronized (VolumeStreamState.class) {
                 // unmute stream that was muted but is not affect by mute anymore
-                if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
+                if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
                         !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
-                    int size = streamState.mDeathHandlers.size();
-                    for (int i = 0; i < size; i++) {
-                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
-                        streamState.mDeathHandlers.get(i).mute_syncVSS(false);
-                    }
+                    streamState.mIsMuted = false;
                 }
             }
         }
@@ -3088,7 +3057,7 @@
      * adjusting volume. If so, this will set the proper ringer mode and volume
      * indices on the stream states.
      */
-    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
+    private int checkForRingerModeChange(int oldIndex, int direction,  int step, boolean isMuted) {
         int result = FLAG_ADJUST_VOLUME;
         int ringerMode = getRingerModeInternal();
 
@@ -3112,6 +3081,15 @@
                         ringerMode = RINGER_MODE_SILENT;
                     }
                 }
+            } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_MUTE) {
+                if (mHasVibrator) {
+                    ringerMode = RINGER_MODE_VIBRATE;
+                } else {
+                    ringerMode = RINGER_MODE_SILENT;
+                }
+                // Setting the ringer mode will toggle mute
+                result &= ~FLAG_ADJUST_VOLUME;
             }
             break;
         case RINGER_MODE_VIBRATE:
@@ -3121,26 +3099,38 @@
                 break;
             }
             if ((direction == AudioManager.ADJUST_LOWER)) {
-                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                // This is the case we were muted with the volume turned up
+                if (oldIndex >= 2 * step && isMuted) {
+                    ringerMode = RINGER_MODE_NORMAL;
+                } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
                     if (VOLUME_SETS_RINGER_MODE_SILENT) {
                         ringerMode = RINGER_MODE_SILENT;
                     } else {
                         result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
                     }
                 }
-            } else if (direction == AudioManager.ADJUST_RAISE) {
+            } else if (direction == AudioManager.ADJUST_RAISE
+                    || direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_UNMUTE) {
                 ringerMode = RINGER_MODE_NORMAL;
             }
             result &= ~FLAG_ADJUST_VOLUME;
             break;
         case RINGER_MODE_SILENT:
-            if (direction == AudioManager.ADJUST_RAISE) {
+            if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
+                // This is the case we were muted with the volume turned up
+                ringerMode = RINGER_MODE_NORMAL;
+            } else if (direction == AudioManager.ADJUST_RAISE
+                    || direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_UNMUTE) {
                 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
                     result |= AudioManager.FLAG_SHOW_SILENT_HINT;
                 } else {
-                  if (mHasVibrator) {
+                  if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
                       ringerMode = RINGER_MODE_VIBRATE;
                   } else {
+                      // If we don't have a vibrator or they were toggling mute
+                      // go straight back to normal.
                       ringerMode = RINGER_MODE_NORMAL;
                   }
                 }
@@ -3184,7 +3174,7 @@
                                         (1 << AudioSystem.STREAM_SYSTEM);
 
         switch (mPlatformType) {
-            case PLATFORM_TELEVISION:
+            case AudioSystem.PLATFORM_TELEVISION:
                 ringerModeAffectedStreams = 0;
                 break;
             default:
@@ -3221,8 +3211,16 @@
     }
 
     private void ensureValidDirection(int direction) {
-        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
-            throw new IllegalArgumentException("Bad direction " + direction);
+        switch (direction) {
+            case AudioManager.ADJUST_LOWER:
+            case AudioManager.ADJUST_RAISE:
+            case AudioManager.ADJUST_SAME:
+            case AudioManager.ADJUST_MUTE:
+            case AudioManager.ADJUST_UNMUTE:
+            case AudioManager.ADJUST_TOGGLE_MUTE:
+                break;
+            default:
+                throw new IllegalArgumentException("Bad direction " + direction);
         }
     }
 
@@ -3238,6 +3236,11 @@
         }
     }
 
+    private boolean isMuteAdjust(int adjust) {
+        return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
+                || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
+    }
+
     private boolean isInCommunication() {
         boolean IsInCall = false;
 
@@ -3264,7 +3267,7 @@
 
     private int getActiveStreamType(int suggestedStreamType) {
         switch (mPlatformType) {
-        case PLATFORM_VOICE:
+        case AudioSystem.PLATFORM_VOICE:
             if (isInCommunication()) {
                 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                         == AudioSystem.FORCE_BT_SCO) {
@@ -3290,7 +3293,7 @@
                 return AudioSystem.STREAM_MUSIC;
             }
             break;
-        case PLATFORM_TELEVISION:
+        case AudioSystem.PLATFORM_TELEVISION:
             if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                     // TV always defaults to STREAM_MUSIC
                     return AudioSystem.STREAM_MUSIC;
@@ -3418,14 +3421,32 @@
         return device;
     }
 
-    public void setWiredDeviceConnectionState(int device, int state, String name) {
+    /*
+     * A class just for packaging up a set of connection parameters.
+     */
+    private class WiredDeviceConnectionState {
+        public int mType;
+        public int mState;
+        public String mAddress;
+        public String mName;
+
+        public WiredDeviceConnectionState(int type, int state, String address, String name) {
+            mType = type;
+            mState = state;
+            mAddress = address;
+            mName = name;
+        }
+    }
+
+    public void setWiredDeviceConnectionState(int type, int state, String address,
+            String name) {
         synchronized (mConnectedDevices) {
-            int delay = checkSendBecomingNoisyIntent(device, state);
+            int delay = checkSendBecomingNoisyIntent(type, state);
             queueMsgUnderWakeLock(mAudioHandler,
                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
-                    device,
-                    state,
-                    name,
+                    0,
+                    0,
+                    new WiredDeviceConnectionState(type, state, address, name),
                     delay);
         }
     }
@@ -3467,11 +3488,11 @@
     public class VolumeStreamState {
         private final int mStreamType;
 
+        private boolean mIsMuted;
         private String mVolumeIndexSettingName;
         private int mIndexMax;
         private final ConcurrentHashMap<Integer, Integer> mIndex =
                                             new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
-        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
 
         private VolumeStreamState(String settingName, int streamType) {
 
@@ -3482,9 +3503,6 @@
             AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
             mIndexMax *= 10;
 
-            // mDeathHandlers must be created before calling readSettings()
-            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
-
             readSettings();
         }
 
@@ -3510,7 +3528,7 @@
                 // only be stale values
                 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
                         (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
-                    int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
+                    int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
                     synchronized (mCameraSoundForced) {
                         if (mCameraSoundForced) {
                             index = mIndexMax;
@@ -3534,7 +3552,7 @@
                     // if no volume stored for current stream and device, use default volume if default
                     // device, continue otherwise
                     int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
-                                            DEFAULT_STREAM_VOLUME[mStreamType] : -1;
+                            AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
                     int index = Settings.System.getIntForUser(
                             mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
                     if (index == -1) {
@@ -3549,7 +3567,7 @@
         // must be called while synchronized VolumeStreamState.class
         public void applyDeviceVolume_syncVSS(int device) {
             int index;
-            if (isMuted_syncVSS()) {
+            if (mIsMuted) {
                 index = 0;
             } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
                     || ((device & mFullVolumeDevices) != 0)) {
@@ -3565,7 +3583,7 @@
                 // apply default volume first: by convention this will reset all
                 // devices volumes in audio policy manager to the supplied value
                 int index;
-                if (isMuted_syncVSS()) {
+                if (mIsMuted) {
                     index = 0;
                 } else {
                     index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
@@ -3578,7 +3596,7 @@
                     Map.Entry entry = (Map.Entry)i.next();
                     int device = ((Integer)entry.getKey()).intValue();
                     if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
-                        if (isMuted_syncVSS()) {
+                        if (mIsMuted) {
                             index = 0;
                         } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
                                 mAvrcpAbsVolSupported)
@@ -3688,14 +3706,20 @@
             }
         }
 
-        public void mute(IBinder cb, boolean state) {
+        public void mute(boolean state) {
             synchronized (VolumeStreamState.class) {
-                VolumeDeathHandler handler = getDeathHandler_syncVSS(cb, state);
-                if (handler == null) {
-                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
-                    return;
+                if (state != mIsMuted) {
+                    mIsMuted = state;
+                    // Set the new mute volume. This propagates the values to
+                    // the audio system, otherwise the volume won't be changed
+                    // at the lower level.
+                    sendMsg(mAudioHandler,
+                            MSG_SET_ALL_VOLUMES,
+                            SENDMSG_QUEUE,
+                            0,
+                            0,
+                            this, 0);
                 }
-                handler.mute_syncVSS(state);
             }
         }
 
@@ -3733,117 +3757,9 @@
             return index;
         }
 
-        private class VolumeDeathHandler implements IBinder.DeathRecipient {
-            private IBinder mICallback; // To be notified of client's death
-            private int mMuteCount; // Number of active mutes for this client
-
-            VolumeDeathHandler(IBinder cb) {
-                mICallback = cb;
-            }
-
-            // must be called while synchronized VolumeStreamState.class
-            public void mute_syncVSS(boolean state) {
-                boolean updateVolume = false;
-                if (state) {
-                    if (mMuteCount == 0) {
-                        // Register for client death notification
-                        try {
-                            // mICallback can be 0 if muted by AudioService
-                            if (mICallback != null) {
-                                mICallback.linkToDeath(this, 0);
-                            }
-                            VolumeStreamState.this.mDeathHandlers.add(this);
-                            // If the stream is not yet muted by any client, set level to 0
-                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
-                                updateVolume = true;
-                            }
-                        } catch (RemoteException e) {
-                            // Client has died!
-                            binderDied();
-                            return;
-                        }
-                    } else {
-                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
-                    }
-                    mMuteCount++;
-                } else {
-                    if (mMuteCount == 0) {
-                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
-                    } else {
-                        mMuteCount--;
-                        if (mMuteCount == 0) {
-                            // Unregister from client death notification
-                            VolumeStreamState.this.mDeathHandlers.remove(this);
-                            // mICallback can be 0 if muted by AudioService
-                            if (mICallback != null) {
-                                mICallback.unlinkToDeath(this, 0);
-                            }
-                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
-                                updateVolume = true;
-                            }
-                        }
-                    }
-                }
-                if (updateVolume) {
-                    sendMsg(mAudioHandler,
-                            MSG_SET_ALL_VOLUMES,
-                            SENDMSG_QUEUE,
-                            0,
-                            0,
-                            VolumeStreamState.this, 0);
-                }
-            }
-
-            public void binderDied() {
-                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
-                synchronized (VolumeStreamState.class) {
-                    if (mMuteCount != 0) {
-                        // Reset all active mute requests from this client.
-                        mMuteCount = 1;
-                        mute_syncVSS(false);
-                    }
-                }
-            }
-        }
-
-        private int muteCount() {
-            int count = 0;
-            int size = mDeathHandlers.size();
-            for (int i = 0; i < size; i++) {
-                count += mDeathHandlers.get(i).mMuteCount;
-            }
-            return count;
-        }
-
-        // must be called while synchronized VolumeStreamState.class
-        private boolean isMuted_syncVSS() {
-            return muteCount() != 0;
-        }
-
-        // must be called while synchronized VolumeStreamState.class
-        private VolumeDeathHandler getDeathHandler_syncVSS(IBinder cb, boolean state) {
-            VolumeDeathHandler handler;
-            int size = mDeathHandlers.size();
-            for (int i = 0; i < size; i++) {
-                handler = mDeathHandlers.get(i);
-                if (cb == handler.mICallback) {
-                    return handler;
-                }
-            }
-            // If this is the first mute request for this client, create a new
-            // client death handler. Otherwise, it is an out of sequence unmute request.
-            if (state) {
-                handler = new VolumeDeathHandler(cb);
-            } else {
-                Log.w(TAG, "stream was not muted by this client");
-                handler = null;
-            }
-            return handler;
-        }
-
         private void dump(PrintWriter pw) {
-            pw.print("   Mute count: ");
-            pw.println(muteCount());
+            pw.print("   Muted: ");
+            pw.println(mIsMuted);
             pw.print("   Max: ");
             pw.println((mIndexMax + 5) / 10);
             pw.print("   Current: ");
@@ -4262,7 +4178,8 @@
                             AudioSystem.setDeviceConnectionState(
                                                             ((Integer)device.getKey()).intValue(),
                                                             AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                            (String)device.getValue());
+                                                            (String)device.getValue(),
+                                                            "unknown-device");
                         }
                     }
                     // Restore call state
@@ -4364,8 +4281,12 @@
                     break;
 
                 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
-                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
-                    mAudioEventWakeLock.release();
+                    {   WiredDeviceConnectionState connectState =
+                            (WiredDeviceConnectionState)msg.obj;
+                        onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
+                                connectState.mAddress, connectState.mName);
+                        mAudioEventWakeLock.release();
+                    }
                     break;
 
                 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
@@ -4434,6 +4355,9 @@
                                                  msg.arg1,
                                                  msg.arg2);
                     break;
+                case MSG_UNMUTE_STREAM:
+                    onUnmuteStream(msg.arg1, msg.arg2);
+                    break;
             }
         }
     }
@@ -4478,7 +4402,8 @@
         setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE,
-                address);
+                address,
+                "a2dp-device");
         // Reset A2DP suspend state each time a new sink is connected
         AudioSystem.setParameters("A2dpSuspended=false");
         mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
@@ -4496,12 +4421,13 @@
         }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address);
+                address,
+                "a2dp-device");
         mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
         synchronized (mCurAudioRoutes) {
             // Remove A2DP routes as well
-            if (mCurAudioRoutes.mBluetoothName != null) {
-                mCurAudioRoutes.mBluetoothName = null;
+            if (mCurAudioRoutes.bluetoothName != null) {
+                mCurAudioRoutes.bluetoothName = null;
                 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                         SENDMSG_NOOP, 0, 0, null, 0);
             }
@@ -4525,7 +4451,8 @@
     private void makeA2dpSrcAvailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE,
-                address);
+                address,
+                "a2dp-device");
         mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
                 address);
     }
@@ -4534,7 +4461,8 @@
     private void makeA2dpSrcUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address);
+                address,
+                "a2dp-device");
         mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
     }
 
@@ -4579,8 +4507,8 @@
                     makeA2dpDeviceUnavailableNow(address);
                 }
                 synchronized (mCurAudioRoutes) {
-                    if (mCurAudioRoutes.mBluetoothName != null) {
-                        mCurAudioRoutes.mBluetoothName = null;
+                    if (mCurAudioRoutes.bluetoothName != null) {
+                        mCurAudioRoutes.bluetoothName = null;
                         sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                                 SENDMSG_NOOP, 0, 0, null, 0);
                     }
@@ -4601,8 +4529,8 @@
                 makeA2dpDeviceAvailable(address);
                 synchronized (mCurAudioRoutes) {
                     String name = btDevice.getAliasName();
-                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
-                        mCurAudioRoutes.mBluetoothName = name;
+                    if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
+                        mCurAudioRoutes.bluetoothName = name;
                         sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                                 SENDMSG_NOOP, 0, 0, null, 0);
                     }
@@ -4650,22 +4578,26 @@
         }
     }
 
-    private boolean handleDeviceConnection(boolean connected, int device, String params) {
+    private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
+        Slog.i(TAG, "handleDeviceConnection(" + connect +
+                " dev:" + Integer.toHexString(device) +
+                " address:" + address +
+                " name:" + deviceName + ")");
         synchronized (mConnectedDevices) {
             boolean isConnected = (mConnectedDevices.containsKey(device) &&
-                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
+                    (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
 
-            if (isConnected && !connected) {
+            if (isConnected && !connect) {
                 AudioSystem.setDeviceConnectionState(device,
                                               AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                                              mConnectedDevices.get(device));
+                                              address, deviceName);
                  mConnectedDevices.remove(device);
                  return true;
-            } else if (!isConnected && connected) {
+            } else if (!isConnected && connect) {
                  AudioSystem.setDeviceConnectionState(device,
                                                       AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                      params);
-                 mConnectedDevices.put(new Integer(device), params);
+                                                      address, deviceName);
+                 mConnectedDevices.put(new Integer(device), address);
                  return true;
             }
         }
@@ -4718,12 +4650,18 @@
         return delay;
     }
 
-    private void sendDeviceConnectionIntent(int device, int state, String name)
+    private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
     {
+        Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
+                " state:0x" + Integer.toHexString(state) +
+                " address:" + address +
+                " name:" + deviceName + ");");
         Intent intent = new Intent();
 
-        intent.putExtra("state", state);
-        intent.putExtra("name", name);
+        intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
+        intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
+        intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
+
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
 
         int connType = 0;
@@ -4742,18 +4680,20 @@
                 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
             connType = AudioRoutesInfo.MAIN_HDMI;
             configureHdmiPlugIntent(intent, state);
+        } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
+            connType = AudioRoutesInfo.MAIN_USB;
         }
 
         synchronized (mCurAudioRoutes) {
             if (connType != 0) {
-                int newConn = mCurAudioRoutes.mMainType;
+                int newConn = mCurAudioRoutes.mainType;
                 if (state != 0) {
                     newConn |= connType;
                 } else {
                     newConn &= ~connType;
                 }
-                if (newConn != mCurAudioRoutes.mMainType) {
-                    mCurAudioRoutes.mMainType = newConn;
+                if (newConn != mCurAudioRoutes.mainType) {
+                    mCurAudioRoutes.mainType = newConn;
                     sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                             SENDMSG_NOOP, 0, 0, null, 0);
                 }
@@ -4768,8 +4708,14 @@
         }
     }
 
-    private void onSetWiredDeviceConnectionState(int device, int state, String name)
+    private void onSetWiredDeviceConnectionState(int device, int state, String address,
+            String deviceName)
     {
+        Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
+                + " state:" + Integer.toHexString(state)
+                + " address:" + address
+                + " deviceName:" + deviceName + ");");
+
         synchronized (mConnectedDevices) {
             if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
@@ -4779,7 +4725,7 @@
             boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
                             (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
                              ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
-            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
+            handleDeviceConnection(state == 1, device, address, deviceName);
             if (state != 0) {
                 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
@@ -4817,8 +4763,8 @@
                     }
                 }
             }
-            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
-                sendDeviceConnectionIntent(device, state, name);
+            if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
+                sendDeviceConnectionIntent(device, state, address, deviceName);
             }
         }
     }
@@ -4942,8 +4888,9 @@
                 }
 
                 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
-                boolean success = handleDeviceConnection(connected, outDevice, address) &&
-                                      handleDeviceConnection(connected, inDevice, address);
+                boolean success =
+                    handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
+                    handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
                 if (success) {
                     synchronized (mScoClients) {
                         if (connected) {
@@ -5078,7 +5025,7 @@
             IAudioPolicyCallback pcb) {
         // permission checks
         if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
-            if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
+            if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
                 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
                             android.Manifest.permission.MODIFY_PHONE_STATE)) {
                     Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
@@ -5546,8 +5493,8 @@
         dumpStreamStates(pw);
         dumpRingerMode(pw);
         pw.println("\nAudio routes:");
-        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
-        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
+        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
+        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
 
         pw.println("\nOther state:");
         pw.print("  mVolumeController="); pw.println(mVolumeController);
@@ -5648,7 +5595,10 @@
                     Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
         }
 
-        public boolean suppressAdjustment(int resolvedStream, int flags) {
+        public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
+            if (isMute) {
+                return false;
+            }
             boolean suppress = false;
             if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
                 final long now = SystemClock.uptimeMillis();
@@ -5801,12 +5751,6 @@
         public void setRingerModeInternal(int ringerMode, String caller) {
             AudioService.this.setRingerModeInternal(ringerMode, caller);
         }
-
-        @Override
-        public void setMasterMuteForUid(boolean state, int flags, String callingPackage, IBinder cb,
-                int uid) {
-            setMasterMuteInternal(state, flags, callingPackage, cb, uid);
-        }
     }
 
     //==========================================================================================
diff --git a/media/java/android/media/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
similarity index 97%
rename from media/java/android/media/FocusRequester.java
rename to services/core/java/com/android/server/audio/FocusRequester.java
index bbe5fd2..49be879 100644
--- a/media/java/android/media/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -14,13 +14,18 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.server.audio;
 
 import android.annotation.NonNull;
-import android.media.MediaFocusControl.AudioFocusDeathHandler;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.IAudioFocusDispatcher;
 import android.os.IBinder;
 import android.util.Log;
 
+import com.android.server.audio.MediaFocusControl.AudioFocusDeathHandler;
+
 import java.io.PrintWriter;
 
 /**
@@ -29,7 +34,7 @@
  * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
  * stack to its release.
  */
-class FocusRequester {
+public class FocusRequester {
 
     // on purpose not using this classe's name, as it will only be used from MediaFocusControl
     private static final String TAG = "MediaFocusControl";
diff --git a/media/java/android/media/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
similarity index 98%
rename from media/java/android/media/MediaFocusControl.java
rename to services/core/java/com/android/server/audio/MediaFocusControl.java
index 6518bd1..24e1ace 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.server.audio;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -32,7 +32,17 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
-import android.media.PlayerRecord.RemotePlaybackState;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IAudioFocusDispatcher;
+import android.media.IAudioService;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteControlDisplay;
+import android.media.IRemoteVolumeObserver;
+import android.media.RemoteControlClient;
+import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.media.audiopolicy.IAudioPolicyCallback;
 import android.net.Uri;
 import android.os.Binder;
@@ -53,6 +63,8 @@
 import android.util.Slog;
 import android.view.KeyEvent;
 
+import com.android.server.audio.PlayerRecord.RemotePlaybackState;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -391,13 +403,6 @@
     // AudioFocus
     //==========================================================================================
 
-    /**
-     * Constant to identify a focus stack entry that is used to hold the focus while the phone
-     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
-     * entering and exiting calls.
-     */
-    protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
-
     private final static Object mAudioFocusLock = new Object();
 
     private final static Object mRingingLock = new Object();
@@ -565,7 +570,7 @@
     }
 
     private boolean isLockedFocusOwner(FocusRequester fr) {
-        return (fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
+        return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
     }
 
     /**
diff --git a/media/java/android/media/PlayerRecord.java b/services/core/java/com/android/server/audio/PlayerRecord.java
similarity index 97%
rename from media/java/android/media/PlayerRecord.java
rename to services/core/java/com/android/server/audio/PlayerRecord.java
index 664ddcf..a7dbbd1 100644
--- a/media/java/android/media/PlayerRecord.java
+++ b/services/core/java/com/android/server/audio/PlayerRecord.java
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.server.audio;
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.media.AudioManager;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteVolumeObserver;
+import android.media.RemoteControlClient;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index f900d0d..87f78c1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -28,6 +28,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
+import android.net.ProxyInfo;
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.net.wifi.WifiInfo;
@@ -656,12 +657,36 @@
         int httpResponseCode = 599;
         try {
             URL url = new URL("http", mServer, "/generate_204");
+            // On networks with a PAC instead of fetching a URL that should result in a 204
+            // reponse, we instead simply fetch the PAC script.  This is done for a few reasons:
+            // 1. At present our PAC code does not yet handle multiple PACs on multiple networks
+            //    until something like https://android-review.googlesource.com/#/c/115180/ lands.
+            //    Network.openConnection() will ignore network-specific PACs and instead fetch
+            //    using NO_PROXY.  If a PAC is in place, the only fetch we know will succeed with
+            //    NO_PROXY is the fetch of the PAC itself.
+            // 2. To proxy the generate_204 fetch through a PAC would require a number of things
+            //    happen before the fetch can commence, namely:
+            //        a) the PAC script be fetched
+            //        b) a PAC script resolver service be fired up and resolve mServer
+            //    Network validation could be delayed until these prerequisities are satisifed or
+            //    could simply be left to race them.  Neither is an optimal solution.
+            // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
+            //    fact block fetching of the generate_204 URL which would lead to false negative
+            //    results for network validation.
+            boolean fetchPac = false;
+            {
+                final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
+                if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
+                    url = new URL(proxyInfo.getPacFileUrl().toString());
+                    fetchPac = true;
+                }
+            }
             if (DBG) {
                 log("Checking " + url.toString() + " on " +
                         mNetworkAgentInfo.networkInfo.getExtraInfo());
             }
             urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url);
-            urlConnection.setInstanceFollowRedirects(false);
+            urlConnection.setInstanceFollowRedirects(fetchPac);
             urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setUseCaches(false);
@@ -695,6 +720,11 @@
                 httpResponseCode = 204;
             }
 
+            if (httpResponseCode == 200 && fetchPac) {
+                if (DBG) log("PAC fetch 200 response interpreted as 204 response.");
+                httpResponseCode = 204;
+            }
+
             sendNetworkConditionsBroadcast(true /* response received */,
                     httpResponseCode != 204 /* isCaptivePortal */,
                     requestTimestamp, responseTimestamp);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bd0e587..709ca4b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -847,9 +847,29 @@
     /**
      * Start legacy VPN, controlling native daemons as needed. Creates a
      * secondary thread to perform connection work, returning quickly.
+     *
+     * Should only be called to respond to Binder requests as this enforces caller permission. Use
+     * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the
+     * permission check only when the caller is trusted (or the call is initiated by the system).
      */
     public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
         enforceControlPermission();
+        long token = Binder.clearCallingIdentity();
+        try {
+            startLegacyVpnPrivileged(profile, keyStore, egress);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check
+     * permissions under the assumption that the caller is the system.
+     *
+     * Callers are responsible for checking permissions if needed.
+     */
+    public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
+            LinkProperties egress) {
         if (!keyStore.isUnlocked()) {
             throw new IllegalStateException("KeyStore isn't unlocked");
         }
@@ -960,10 +980,10 @@
     }
 
     private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
-        stopLegacyVpn();
+        stopLegacyVpnPrivileged();
 
-        // Prepare for the new request. This also checks the caller.
-        prepare(null, VpnConfig.LEGACY_VPN);
+        // Prepare for the new request.
+        prepareInternal(VpnConfig.LEGACY_VPN);
         updateState(DetailedState.CONNECTING, "startLegacyVpn");
 
         // Start a new LegacyVpnRunner and we are done!
@@ -971,7 +991,8 @@
         mLegacyVpnRunner.start();
     }
 
-    public synchronized void stopLegacyVpn() {
+    /** Stop legacy VPN. Permissions must be checked by callers. */
+    public synchronized void stopLegacyVpnPrivileged() {
         if (mLegacyVpnRunner != null) {
             mLegacyVpnRunner.exit();
             mLegacyVpnRunner = null;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 6e61e41..4e075c3 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -37,7 +37,6 @@
 import android.opengl.EGLSurface;
 import android.opengl.GLES20;
 import android.opengl.GLES11Ext;
-import android.util.FloatMath;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Surface.OutOfResourcesException;
@@ -372,13 +371,13 @@
             GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
 
             // Draw the frame.
-            float one_minus_level = 1 - level;
-            float cos = FloatMath.cos((float)Math.PI * one_minus_level);
-            float sign = cos < 0 ? -1 : 1;
-            float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
-            float saturation = FloatMath.pow(level, 4);
-            float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
-            float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
+            double one_minus_level = 1 - level;
+            double cos = Math.cos(Math.PI * one_minus_level);
+            double sign = cos < 0 ? -1 : 1;
+            float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
+            float saturation = (float) Math.pow(level, 4);
+            float scale = (float) ((-Math.pow(one_minus_level, 2) + 1) * 0.1d + 0.9d);
+            float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
             drawFaded(opacity, 1.f / gamma, saturation, scale);
             if (checkGlErrors("drawFrame")) {
                 return false;
diff --git a/services/core/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
index c0eee69..0074119 100644
--- a/services/core/java/com/android/server/firewall/SenderFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderFilter.java
@@ -45,7 +45,8 @@
 
         IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            return (pm.getFlagsForUid(callerUid) & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+            return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                    != 0;
         } catch (RemoteException ex) {
             Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
                     ex);
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 59d5605..7f48768 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -62,11 +62,6 @@
     void process(ActiveSource newActive, int deviceType) {
         // Seq #17
         HdmiCecLocalDeviceTv tv = mSource;
-        ActiveSource activeSource = tv.getActiveSource();
-        if (activeSource.equals(newActive)) {
-            invokeCallback(HdmiControlManager.RESULT_SUCCESS);
-            return;
-        }
         HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
         if (device == null) {
             tv.startNewDeviceAction(newActive, deviceType);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 0c86aed..e434f39 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -214,6 +214,10 @@
     //     values which denotes the device type in HDMI Spec 1.4.
     static final String PROPERTY_DEVICE_TYPE = "ro.hdmi.device_type";
 
+    // Set to false to allow playback device to go to suspend mode even
+    // when it's an active source. True by default.
+    static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
+
     static final int RECORDING_TYPE_DIGITAL_RF = 1;
     static final int RECORDING_TYPE_ANALOGUE_RF = 2;
     static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index ce52920..1e43670 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -38,9 +38,11 @@
 
     // Used to keep the device awake while it is the active source. For devices that
     // cannot wake up via CEC commands, this address the inconvenience of having to
-    // turn them on.
+    // turn them on. True by default, and can be disabled (i.e. device can go to sleep
+    // in active device status) by explicitly setting the system property
+    // persist.sys.hdmi.keep_awake to false.
     // Lazily initialized - should call getWakeLock() to get the instance.
-    private WakeLock mWakeLock;
+    private ActiveWakeLock mWakeLock;
 
     HdmiCecLocalDevicePlayback(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
@@ -55,10 +57,6 @@
         mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                 mAddress, mService.getVendorId()));
         startQueuedActions();
-
-        // Switch TV input after bootup.
-        setActiveSource(true);
-        maySendActiveSource(Constants.ADDR_TV);
     }
 
     @Override
@@ -146,19 +144,30 @@
         mIsActiveSource = on;
         if (on) {
             getWakeLock().acquire();
-            HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
         } else {
             getWakeLock().release();
-            HdmiLogger.debug("Wake lock released");
         }
     }
 
     @ServiceThreadOnly
-    private WakeLock getWakeLock() {
+    private ActiveWakeLock getWakeLock() {
         assertRunOnServiceThread();
         if (mWakeLock == null) {
-            mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-            mWakeLock.setReferenceCounted(false);
+            if (SystemProperties.getBoolean(Constants.PROPERTY_KEEP_AWAKE, true)) {
+                mWakeLock = new SystemWakeLock();
+            } else {
+                // Create a dummy lock object that doesn't do anything about wake lock,
+                // hence allows the device to go to sleep even if it's the active source.
+                mWakeLock = new ActiveWakeLock() {
+                    @Override
+                    public void acquire() { }
+                    @Override
+                    public void release() { }
+                    @Override
+                    public boolean isHeld() { return false; }
+                };
+                HdmiLogger.debug("No wakelock is used to keep the display on.");
+            }
         }
         return mWakeLock;
     }
@@ -262,4 +271,36 @@
         super.dump(pw);
         pw.println("mIsActiveSource: " + mIsActiveSource);
     }
+
+    // Wrapper interface over PowerManager.WakeLock
+    private interface ActiveWakeLock {
+        void acquire();
+        void release();
+        boolean isHeld();
+    }
+
+    private class SystemWakeLock implements ActiveWakeLock {
+        private final WakeLock mWakeLock;
+        public SystemWakeLock() {
+            mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+            mWakeLock.setReferenceCounted(false);
+        }
+
+        @Override
+        public void acquire() {
+            mWakeLock.acquire();
+            HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
+        }
+
+        @Override
+        public void release() {
+            mWakeLock.release();
+            HdmiLogger.debug("Wake lock released");
+        }
+
+        @Override
+        public boolean isHeld() {
+            return mWakeLock.isHeld();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 43ef457..4f458e6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.HdmiRecordSources;
 import android.hardware.hdmi.HdmiTimerRecordSources;
 import android.hardware.hdmi.IHdmiControlCallback;
@@ -431,11 +432,15 @@
             return;
         }
         List<SendKeyAction> action = getActions(SendKeyAction.class);
+        int logicalAddress = findKeyReceiverAddress();
+        if (logicalAddress == mAddress) {
+            Slog.w(TAG, "Discard key event to itself :" + keyCode + " pressed:" + isPressed);
+            return;
+        }
         if (!action.isEmpty()) {
             action.get(0).processKeyEvent(keyCode, isPressed);
         } else {
             if (isPressed) {
-                int logicalAddress = findKeyReceiverAddress();
                 if (logicalAddress != Constants.ADDR_INVALID) {
                     addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
                     return;
@@ -580,6 +585,12 @@
         if (!isInDeviceList(address, path)) {
             handleNewDeviceAtTheTailOfActivePath(path);
         }
+
+        // Add the device ahead with default information to handle <Active Source>
+        // promptly, rather than waiting till the new device action is finished.
+        HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo(address, path, getPortId(path), type,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(address));
+        addCecDevice(deviceInfo);
         startNewDeviceAction(ActiveSource.of(address, path), type);
         return true;
     }
@@ -878,11 +889,22 @@
         return oldStatus;
     }
 
+    @ServiceThreadOnly
+    private void updateArcFeatureStatus(int portId, boolean isConnected) {
+        assertRunOnServiceThread();
+        // HEAC 2.4, HEACT 5-15
+        // Should not activate ARC if +5V status is false.
+        HdmiPortInfo portInfo = mService.getPortInfo(portId);
+        if (portInfo.isArcSupported()) {
+            changeArcFeatureEnabled(isConnected);
+        }
+    }
+
     private void notifyArcStatusToAudioService(boolean enabled) {
         // Note that we don't set any name to ARC.
         mService.getAudioManager().setWiredDeviceConnectionState(
                 AudioSystem.DEVICE_OUT_HDMI_ARC,
-                enabled ? 1 : 0, "");
+                enabled ? 1 : 0, "", "");
     }
 
     /**
@@ -1456,6 +1478,25 @@
     }
 
     /**
+     * Returns the {@link HdmiDeviceInfo} instance whose physical address matches
+     * the given routing path. This is the version accessible safely from threads
+     * other than service thread.
+     *
+     * @param path routing path or physical address
+     * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null
+     */
+    HdmiDeviceInfo getSafeDeviceInfoByPath(int path) {
+        synchronized (mLock) {
+            for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+                if (info.getPhysicalAddress() == path) {
+                    return info;
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
      * Whether a device of the specified physical address and logical address exists
      * in a device info list. However, both are minimal condition and it could
      * be different device from the original one.
@@ -1465,7 +1506,7 @@
      * @return true if exist; otherwise false
      */
     @ServiceThreadOnly
-    private boolean isInDeviceList(int logicalAddress, int physicalAddress) {
+    boolean isInDeviceList(int logicalAddress, int physicalAddress) {
         assertRunOnServiceThread();
         HdmiDeviceInfo device = getCecDeviceInfo(logicalAddress);
         if (device == null) {
@@ -1490,6 +1531,7 @@
             // It covers seq #40, #43.
             hotplugActions.get(0).pollAllDevicesNow();
         }
+        updateArcFeatureStatus(portId, connected);
     }
 
     private void removeCecSwitches(int portId) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9f78c61..49a96d8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1196,7 +1196,7 @@
             }
             int activePath = tv.getActivePath();
             if (activePath != HdmiDeviceInfo.PATH_INVALID) {
-                HdmiDeviceInfo info = tv.getDeviceInfoByPath(activePath);
+                HdmiDeviceInfo info = tv.getSafeDeviceInfoByPath(activePath);
                 return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId());
             }
             return null;
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 722be71..1bbd038 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -38,6 +38,7 @@
 
     private static final int POLLING_INTERVAL_MS = 5000;
     private static final int TIMEOUT_COUNT = 3;
+    private static final int AVR_COUNT_MAX = 3;
 
     // State in which waits for next polling
     private static final int STATE_WAIT_FOR_NEXT_POLLING = 1;
@@ -48,6 +49,12 @@
 
     private int mTimeoutCount = 0;
 
+    // Counter used to ensure the connection to AVR is stable. Occasional failure to get
+    // polling response from AVR despite its presence leads to unstable status flipping.
+    // This is a workaround to deal with it, by removing the device only if the removal
+    // is detected {@code AVR_COUNT_MAX} times in a row.
+    private int mAvrStatusCount = 0;
+
     /**
      * Constructor
      *
@@ -148,10 +155,22 @@
         BitSet removed = complement(currentInfos, polledResult);
         int index = -1;
         while ((index = removed.nextSetBit(index + 1)) != -1) {
+            if (index == Constants.ADDR_AUDIO_SYSTEM) {
+                ++mAvrStatusCount;
+                Slog.w(TAG, "Ack not returned from AVR. count: " + mAvrStatusCount);
+                if (mAvrStatusCount < AVR_COUNT_MAX) {
+                    continue;
+                }
+            }
             Slog.v(TAG, "Remove device by hot-plug detection:" + index);
             removeDevice(index);
         }
 
+        // Reset the counter if the ack is returned from AVR.
+        if (!removed.get(Constants.ADDR_AUDIO_SYSTEM)) {
+            mAvrStatusCount = 0;
+        }
+
         // Next, check added devices.
         BitSet added = complement(polledResult, currentInfos);
         index = -1;
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 3d64cc5..6753368 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -163,6 +163,12 @@
     }
 
     private void addDeviceInfo() {
+        // The device should be in the device list with default information.
+        if (!tv().isInDeviceList(mDeviceLogicalAddress, mDevicePhysicalAddress)) {
+            Slog.w(TAG, String.format("Device not found (%02x, %04x)",
+                    mDeviceLogicalAddress, mDevicePhysicalAddress));
+            return;
+        }
         if (mDisplayName == null) {
             mDisplayName = HdmiUtils.getDefaultDeviceName(mDeviceLogicalAddress);
         }
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 2a1f7d6..65693b4 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -25,7 +25,6 @@
 import com.android.internal.R;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
 
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
@@ -72,7 +71,6 @@
 import android.provider.Telephony.Carriers;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.SmsMessage;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
@@ -91,7 +89,6 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Date;
-import java.util.List;
 import java.util.Map.Entry;
 import java.util.Properties;
 
@@ -395,7 +392,7 @@
 
     private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
         @Override
-        public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
+        public void addGpsStatusListener(IGpsStatusListener listener) {
             mListenerHelper.addListener(listener);
         }
 
@@ -681,7 +678,7 @@
         mListenerHelper = new GpsStatusListenerHelper(mHandler) {
             @Override
             protected boolean isAvailableInPlatform() {
-                return GpsLocationProvider.isSupported();
+                return isSupported();
             }
 
             @Override
@@ -788,9 +785,7 @@
         }
 
         if (info != null) {
-            boolean dataEnabled = TelephonyManager.getIntWithSubId(mContext.getContentResolver(),
-                    Settings.Global.MOBILE_DATA, SubscriptionManager.getDefaultSubId(),
-                    1) == 1;
+            boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
             boolean networkAvailable = info.isAvailable() && dataEnabled;
             String defaultApn = getSelectedApn();
             if (defaultApn == null) {
@@ -1027,6 +1022,9 @@
             if (mC2KServerHost != null) {
                 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
             }
+
+            mGpsMeasurementsProvider.onGpsEnabledChanged();
+            mGpsNavigationMessageProvider.onGpsEnabledChanged();
         } else {
             synchronized (mLock) {
                 mEnabled = false;
@@ -1060,6 +1058,9 @@
 
         // do this before releasing wakelock
         native_cleanup();
+
+        mGpsMeasurementsProvider.onGpsEnabledChanged();
+        mGpsNavigationMessageProvider.onGpsEnabledChanged();
     }
 
     @Override
@@ -1479,9 +1480,7 @@
         }
 
         if (wasNavigating != mNavigating) {
-            mListenerHelper.onGpsEnabledChanged(mNavigating);
-            mGpsMeasurementsProvider.onGpsEnabledChanged(mNavigating);
-            mGpsNavigationMessageProvider.onGpsEnabledChanged(mNavigating);
+            mListenerHelper.onStatusChanged(mNavigating);
 
             // send an intent to notify that the GPS has been enabled or disabled
             Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
index 0514e0c..b327ca2 100644
--- a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -33,7 +33,7 @@
         extends RemoteListenerHelper<IGpsMeasurementsListener> {
     private static final String TAG = "GpsMeasurementsProvider";
 
-    public GpsMeasurementsProvider(Handler handler) {
+    protected GpsMeasurementsProvider(Handler handler) {
         super(handler, TAG);
     }
 
@@ -49,15 +49,19 @@
     }
 
     public void onCapabilitiesUpdated(boolean isGpsMeasurementsSupported) {
-        int status = isGpsMeasurementsSupported ?
-                GpsMeasurementsEvent.STATUS_READY :
-                GpsMeasurementsEvent.STATUS_NOT_SUPPORTED;
-        setSupported(isGpsMeasurementsSupported, new StatusChangedOperation(status));
+        setSupported(isGpsMeasurementsSupported);
+        updateResult();
+    }
+
+    public void onGpsEnabledChanged() {
+        if (tryUpdateRegistrationWithService()) {
+            updateResult();
+        }
     }
 
     @Override
     protected ListenerOperation<IGpsMeasurementsListener> getHandlerOperation(int result) {
-        final int status;
+        int status;
         switch (result) {
             case RESULT_SUCCESS:
                 status = GpsMeasurementsEvent.STATUS_READY;
@@ -70,6 +74,8 @@
             case RESULT_GPS_LOCATION_DISABLED:
                 status = GpsMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
                 break;
+            case RESULT_UNKNOWN:
+                return null;
             default:
                 Log.v(TAG, "Unhandled addListener result: " + result);
                 return null;
@@ -77,15 +83,8 @@
         return new StatusChangedOperation(status);
     }
 
-    @Override
-    protected void handleGpsEnabledChanged(boolean enabled) {
-        int status = enabled ?
-                GpsMeasurementsEvent.STATUS_READY :
-                GpsMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
-        foreach(new StatusChangedOperation(status));
-    }
-
-    private class StatusChangedOperation implements ListenerOperation<IGpsMeasurementsListener> {
+    private static class StatusChangedOperation
+            implements ListenerOperation<IGpsMeasurementsListener> {
         private final int mStatus;
 
         public StatusChangedOperation(int status) {
diff --git a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
index 13d22fc..e6bbe56 100644
--- a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
@@ -33,7 +33,7 @@
         extends RemoteListenerHelper<IGpsNavigationMessageListener> {
     private static final String TAG = "GpsNavigationMessageProvider";
 
-    public GpsNavigationMessageProvider(Handler handler) {
+    protected GpsNavigationMessageProvider(Handler handler) {
         super(handler, TAG);
     }
 
@@ -50,15 +50,19 @@
     }
 
     public void onCapabilitiesUpdated(boolean isGpsNavigationMessageSupported) {
-        int status = isGpsNavigationMessageSupported ?
-                GpsNavigationMessageEvent.STATUS_READY :
-                GpsNavigationMessageEvent.STATUS_NOT_SUPPORTED;
-        setSupported(isGpsNavigationMessageSupported, new StatusChangedOperation(status));
+        setSupported(isGpsNavigationMessageSupported);
+        updateResult();
+    }
+
+    public void onGpsEnabledChanged() {
+        if (tryUpdateRegistrationWithService()) {
+            updateResult();
+        }
     }
 
     @Override
     protected ListenerOperation<IGpsNavigationMessageListener> getHandlerOperation(int result) {
-        final int status;
+        int status;
         switch (result) {
             case RESULT_SUCCESS:
                 status = GpsNavigationMessageEvent.STATUS_READY;
@@ -71,6 +75,8 @@
             case RESULT_GPS_LOCATION_DISABLED:
                 status = GpsNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
                 break;
+            case RESULT_UNKNOWN:
+                return null;
             default:
                 Log.v(TAG, "Unhandled addListener result: " + result);
                 return null;
@@ -78,15 +84,7 @@
         return new StatusChangedOperation(status);
     }
 
-    @Override
-    protected void handleGpsEnabledChanged(boolean enabled) {
-        int status = enabled ?
-                GpsNavigationMessageEvent.STATUS_READY :
-                GpsNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
-        foreach(new StatusChangedOperation(status));
-    }
-
-    private class StatusChangedOperation
+    private static class StatusChangedOperation
             implements ListenerOperation<IGpsNavigationMessageListener> {
         private final int mStatus;
 
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
index 376b4a5..53ff6c2 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -24,14 +24,9 @@
  * Implementation of a handler for {@link IGpsStatusListener}.
  */
 abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
-    public GpsStatusListenerHelper(Handler handler) {
+    protected GpsStatusListenerHelper(Handler handler) {
         super(handler, "GpsStatusListenerHelper");
-
-        Operation nullOperation = new Operation() {
-            @Override
-            public void execute(IGpsStatusListener iGpsStatusListener) throws RemoteException {}
-        };
-        setSupported(GpsLocationProvider.isSupported(), nullOperation);
+        setSupported(GpsLocationProvider.isSupported());
     }
 
     @Override
@@ -47,10 +42,9 @@
         return null;
     }
 
-    @Override
-    protected void handleGpsEnabledChanged(boolean enabled) {
+    public void onStatusChanged(boolean isNavigating) {
         Operation operation;
-        if (enabled) {
+        if (isNavigating) {
             operation = new Operation() {
                 @Override
                 public void execute(IGpsStatusListener listener) throws RemoteException {
@@ -114,5 +108,5 @@
         foreach(operation);
     }
 
-    private abstract class Operation implements ListenerOperation<IGpsStatusListener> { }
+    private interface Operation extends ListenerOperation<IGpsStatusListener> {}
 }
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 402b601..ec2828b 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -26,26 +26,31 @@
 import android.util.Log;
 
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * A helper class, that handles operations in remote listeners, and tracks for remote process death.
  */
 abstract class RemoteListenerHelper<TListener extends IInterface> {
+
     protected static final int RESULT_SUCCESS = 0;
     protected static final int RESULT_NOT_AVAILABLE = 1;
     protected static final int RESULT_NOT_SUPPORTED = 2;
     protected static final int RESULT_GPS_LOCATION_DISABLED = 3;
     protected static final int RESULT_INTERNAL_ERROR = 4;
+    protected static final int RESULT_UNKNOWN = 5;
 
     private final Handler mHandler;
     private final String mTag;
 
-    private final HashMap<IBinder, LinkedListener> mListenerMap = new HashMap<>();
+    private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
 
     private boolean mIsRegistered;
     private boolean mHasIsSupported;
     private boolean mIsSupported;
 
+    private int mLastReportedResult = RESULT_UNKNOWN;
+
     protected RemoteListenerHelper(Handler handler, String name) {
         Preconditions.checkNotNull(name);
         mHandler = handler;
@@ -110,33 +115,11 @@
         }
     }
 
-    public void onGpsEnabledChanged(boolean enabled) {
-        // handle first the sub-class implementation, so any error in registration can take
-        // precedence
-        handleGpsEnabledChanged(enabled);
-        synchronized (mListenerMap) {
-            if (!enabled) {
-                tryUnregister();
-                return;
-            }
-            if (mListenerMap.isEmpty()) {
-                return;
-            }
-            if (tryRegister()) {
-                // registration was successful, there is no need to update the state
-                return;
-            }
-            ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
-            foreachUnsafe(operation);
-        }
-    }
-
     protected abstract boolean isAvailableInPlatform();
     protected abstract boolean isGpsEnabled();
     protected abstract boolean registerWithService();
     protected abstract void unregisterFromService();
     protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
-    protected abstract void handleGpsEnabledChanged(boolean enabled);
 
     protected interface ListenerOperation<TListener extends IInterface> {
         void execute(TListener listener) throws RemoteException;
@@ -148,11 +131,40 @@
         }
     }
 
-    protected void setSupported(boolean value, ListenerOperation<TListener> notifier) {
+    protected void setSupported(boolean value) {
         synchronized (mListenerMap) {
             mHasIsSupported = true;
             mIsSupported = value;
-            foreachUnsafe(notifier);
+        }
+    }
+
+    protected boolean tryUpdateRegistrationWithService() {
+        synchronized (mListenerMap) {
+            if (!isGpsEnabled()) {
+                tryUnregister();
+                return true;
+            }
+            if (mListenerMap.isEmpty()) {
+                return true;
+            }
+            if (tryRegister()) {
+                // registration was successful, there is no need to update the state
+                return true;
+            }
+            ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
+            foreachUnsafe(operation);
+            return false;
+        }
+    }
+
+    protected void updateResult() {
+        synchronized (mListenerMap) {
+            int newResult = calculateCurrentResultUnsafe();
+            if (mLastReportedResult == newResult) {
+                return;
+            }
+            foreachUnsafe(getHandlerOperation(newResult));
+            mLastReportedResult = newResult;
         }
     }
 
@@ -183,6 +195,24 @@
         mIsRegistered = false;
     }
 
+    private int calculateCurrentResultUnsafe() {
+        // update statuses we already know about, starting from the ones that will never change
+        if (!isAvailableInPlatform()) {
+            return RESULT_NOT_AVAILABLE;
+        }
+        if (!mHasIsSupported || mListenerMap.isEmpty()) {
+            // we'll update once we have a supported status available
+            return RESULT_UNKNOWN;
+        }
+        if (!mIsSupported) {
+            return RESULT_NOT_SUPPORTED;
+        }
+        if (!isGpsEnabled()) {
+            return RESULT_GPS_LOCATION_DISABLED;
+        }
+        return RESULT_SUCCESS;
+    }
+
     private class LinkedListener implements IBinder.DeathRecipient {
         private final TListener mListener;
 
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index da63caa..df31158 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -250,77 +250,37 @@
         if (isPlaybackActive(false) || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
         }
-        boolean isMute = direction == MediaSessionManager.DIRECTION_MUTE;
-        if (direction > 1) {
-            direction = 1;
-        } else if (direction < -1) {
-            direction = -1;
-        }
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
             if (mUseMasterVolume) {
                 // If this device only uses master volume and playback is local
                 // just adjust the master volume and return.
-                boolean isMasterMute = mAudioManager.isMasterMute();
-                if (isMute) {
-                    mAudioManagerInternal.setMasterMuteForUid(!isMasterMute,
-                            flags, packageName, mService.mICallback, uid);
-                } else {
-                    mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
-                            uid);
-                    if (isMasterMute) {
-                        mAudioManagerInternal.setMasterMuteForUid(false,
-                                flags, packageName, mService.mICallback, uid);
-                    }
-                }
+                mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
+                        uid);
                 return;
             }
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
-            boolean isStreamMute = mAudioManager.isStreamMute(stream);
             if (useSuggested) {
                 if (AudioSystem.isStreamActive(stream, 0)) {
-                    if (isMute) {
-                        mAudioManager.setStreamMute(stream, !isStreamMute);
-                    } else {
-                        mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
-                                flags, packageName, uid);
-                        if (isStreamMute && direction != 0) {
-                            mAudioManager.setStreamMute(stream, false);
-                        }
-                    }
+                    mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
+                            flags, packageName, uid);
                 } else {
                     flags |= previousFlagPlaySound;
-                    isStreamMute =
-                            mAudioManager.isStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE);
-                    if (isMute) {
-                        mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                                !isStreamMute);
-                    } else {
-                        mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
-                                AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
-                                uid);
-                        if (isStreamMute && direction != 0) {
-                            mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                                    false);
-                        }
-                    }
+                    mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
+                            AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
+                            uid);
                 }
             } else {
-                if (isMute) {
-                    mAudioManager.setStreamMute(stream, !isStreamMute);
-                } else {
-                    mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
-                            packageName, uid);
-                    if (isStreamMute && direction != 0) {
-                        mAudioManager.setStreamMute(stream, false);
-                    }
-                }
+                mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
+                        packageName, uid);
             }
         } else {
             if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
                 // Nothing to do, the volume cannot be changed
                 return;
             }
-            if (isMute) {
+            if (direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_MUTE
+                    || direction == AudioManager.ADJUST_UNMUTE) {
                 Log.w(TAG, "Muting remote playback is not supported");
                 return;
             }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 667d02a..1a0f81d 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -742,6 +742,10 @@
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
+            if (DEBUG) {
+                Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+                        + keyEvent);
+            }
 
             try {
                 synchronized (mLock) {
@@ -823,7 +827,7 @@
                 pw.println("User Records:");
                 count = mUserRecords.size();
                 for (int i = 0; i < count; i++) {
-                    UserRecord user = mUserRecords.get(i);
+                    UserRecord user = mUserRecords.get(mUserRecords.keyAt(i));
                     user.dumpLocked(pw, "");
                 }
             }
@@ -872,30 +876,10 @@
                 try {
                     String packageName = getContext().getOpPackageName();
                     if (mUseMasterVolume) {
-                        boolean isMasterMute = mAudioService.isMasterMute();
-                        if (direction == MediaSessionManager.DIRECTION_MUTE) {
-                            mAudioService.setMasterMute(!isMasterMute, flags, packageName, mICallback);
-                        } else {
                             mAudioService.adjustMasterVolume(direction, flags, packageName);
-                            // Do not call setMasterMute when direction = 0 which is used just to
-                            // show the UI.
-                            if (isMasterMute && direction != 0) {
-                                mAudioService.setMasterMute(false, flags, packageName, mICallback);
-                            }
-                        }
                     } else {
-                        boolean isStreamMute = mAudioService.isStreamMute(suggestedStream);
-                        if (direction == MediaSessionManager.DIRECTION_MUTE) {
-                            mAudioManager.setStreamMute(suggestedStream, !isStreamMute);
-                        } else {
-                            mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
-                                    flags, packageName);
-                            // Do not call setStreamMute when direction = 0 which is used just to
-                            // show the UI.
-                            if (isStreamMute && direction != 0) {
-                                mAudioManager.setStreamMute(suggestedStream, false);
-                            }
-                        }
+                        mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
+                                flags, packageName);
                     }
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error adjusting default volume.", e);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index e9b3f8b..bfdc400 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -98,6 +98,11 @@
     @Override
     public void onSwitchUser(int userId) {
         mMediaRouter.rebindAsUser(userId);
+        synchronized (mLock) {
+            if (mProjectionGrant != null) {
+                mProjectionGrant.stop();
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3a1e4a4..752614f 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -140,7 +140,7 @@
         if (egressDisconnected || egressChanged) {
             clearSourceRulesLocked();
             mAcceptedEgressIface = null;
-            mVpn.stopLegacyVpn();
+            mVpn.stopLegacyVpnPrivileged();
         }
         if (egressDisconnected) {
             hideNotification();
@@ -163,7 +163,9 @@
 
                 mAcceptedEgressIface = egressProp.getInterfaceName();
                 try {
-                    mVpn.startLegacyVpn(mProfile, KeyStore.getInstance(), egressProp);
+                    // Use the privileged method because Lockdown VPN is initiated by the system, so
+                    // no additional permission checks are necessary.
+                    mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
                     Slog.e(TAG, "Failed to start VPN", e);
@@ -250,7 +252,7 @@
         mAcceptedEgressIface = null;
         mErrorCount = 0;
 
-        mVpn.stopLegacyVpn();
+        mVpn.stopLegacyVpnPrivileged();
         try {
             mNetService.setFirewallEgressDestRule(mProfile.server, 500, false);
             mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false);
diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
index 8f0f935..e87546c 100644
--- a/services/core/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/core/java/com/android/server/pm/GrantedPermissions.java
@@ -21,13 +21,15 @@
 
 class GrantedPermissions {
     int pkgFlags;
+    int pkgPrivateFlags;
 
     ArraySet<String> grantedPermissions = new ArraySet<String>();
 
     int[] gids;
 
-    GrantedPermissions(int pkgFlags) {
+    GrantedPermissions(int pkgFlags, int pkgPrivateFlags) {
         setFlags(pkgFlags);
+        setPrivateFlags(pkgPrivateFlags);
     }
 
     @SuppressWarnings("unchecked")
@@ -43,8 +45,12 @@
     void setFlags(int pkgFlags) {
         this.pkgFlags = pkgFlags
                 & (ApplicationInfo.FLAG_SYSTEM
-                        | ApplicationInfo.FLAG_PRIVILEGED
-                        | ApplicationInfo.FLAG_FORWARD_LOCK
                         | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
     }
+
+    void setPrivateFlags(int pkgPrivateFlags) {
+        this.pkgPrivateFlags = pkgPrivateFlags
+                & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+                        | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e4675fd..c3f1418 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1299,17 +1299,17 @@
         mMetrics = new DisplayMetrics();
         mSettings = new Settings(context);
         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
 
         // TODO: add a property to control this?
         long dexOptLRUThresholdInMinutes;
@@ -2124,6 +2124,7 @@
                 pkg = new PackageParser.Package(packageName);
                 pkg.applicationInfo.packageName = packageName;
                 pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
+                pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
                 pkg.applicationInfo.dataDir =
                         getDataPathForPackage(packageName, 0).getPath();
                 pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
@@ -2966,7 +2967,7 @@
         }
         // reader
         synchronized (mPackages) {
-            final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
+            final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
             if (suid == null) {
                 return -1;
             }
@@ -2990,6 +2991,21 @@
     }
 
     @Override
+    public int getPrivateFlagsForUid(int uid) {
+        synchronized (mPackages) {
+            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+            if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+                return sus.pkgPrivateFlags;
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return ps.pkgPrivateFlags;
+            }
+        }
+        return 0;
+    }
+
+    @Override
     public boolean isUidPrivileged(int uid) {
         uid = UserHandle.getAppId(uid);
         // reader
@@ -3381,7 +3397,7 @@
                 if (resolveInfo != null) {
                     List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                     result.add(resolveInfo);
-                    return result;
+                    return filterIfNotPrimaryUser(result, userId);
                 }
                 // Check for cross profile results.
                 resolveInfo = queryCrossProfileIntents(
@@ -3394,17 +3410,38 @@
                     result.add(resolveInfo);
                     Collections.sort(result, mResolvePrioritySorter);
                 }
-                return result;
+                return filterIfNotPrimaryUser(result, userId);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
-                return mActivities.queryIntentForPackage(intent, resolvedType, flags,
-                        pkg.activities, userId);
+                return filterIfNotPrimaryUser(
+                        mActivities.queryIntentForPackage(
+                                intent, resolvedType, flags, pkg.activities, userId),
+                        userId);
             }
             return new ArrayList<ResolveInfo>();
         }
     }
 
+    /**
+     * Filter out activities with primaryUserOnly flag set, when current user is not the owner.
+     *
+     * @return filtered list
+     */
+    private List<ResolveInfo> filterIfNotPrimaryUser(List<ResolveInfo> resolveInfos, int userId) {
+        if (userId == UserHandle.USER_OWNER) {
+            return resolveInfos;
+        }
+        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
+            ResolveInfo info = resolveInfos.get(i);
+            if ((info.activityInfo.flags & ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
+                resolveInfos.remove(i);
+            }
+        }
+        return resolveInfos;
+    }
+
+
     private ResolveInfo querySkipCurrentProfileIntents(
             List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
             int flags, int sourceUserId) {
@@ -4288,9 +4325,9 @@
             // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
             // it needs to drop FLAG_PRIVILEGED.
             if (locationIsPrivileged(scanFile)) {
-                updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+                updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             } else {
-                updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;
+                updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             }
 
             if (ps != null && !ps.codePath.equals(scanFile)) {
@@ -4354,7 +4391,7 @@
 
             // An updated privileged app will not have the PARSE_IS_PRIVILEGED
             // flag set initially
-            if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+            if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                 parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
             }
         }
@@ -5294,7 +5331,7 @@
         }
 
         if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         }
 
         if (mCustomResolverComponentName != null &&
@@ -5368,7 +5405,7 @@
         // writer
         synchronized (mPackages) {
             if (pkg.mSharedUserId != null) {
-                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
+                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
                 if (suid == null) {
                     throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                             "Creating application package " + pkg.packageName
@@ -5442,7 +5479,8 @@
                     destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
                     pkg.applicationInfo.primaryCpuAbi,
                     pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.applicationInfo.flags, user, false);
+                    pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
+                    user, false);
             if (pkgSetting == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                         "Creating application package " + pkg.packageName + " failed");
@@ -8638,7 +8676,11 @@
                         if (DEBUG_INSTALL) Log.v(TAG, "token " + token
                                 + " to BM for possible restore");
                         try {
-                            bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+                            if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {
+                                bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+                            } else {
+                                doRestore = false;
+                            }
                         } catch (RemoteException e) {
                             // can't happen; the backup manager is local
                         } catch (Exception e) {
@@ -10333,7 +10375,8 @@
         boolean disabledSystem = false;
         boolean updatedSettings = false;
         parseFlags |= PackageParser.PARSE_IS_SYSTEM;
-        if ((deletedPackage.applicationInfo.flags&ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+        if ((deletedPackage.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                != 0) {
             parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
         }
         String packageName = deletedPackage.packageName;
@@ -10691,15 +10734,15 @@
     }
 
     private static boolean isForwardLocked(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
 
     private static boolean isForwardLocked(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+        return (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
 
     private boolean isForwardLocked(PackageSetting ps) {
-        return (ps.pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
+        return (ps.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
 
     private static boolean isMultiArch(PackageSetting ps) {
@@ -10727,7 +10770,7 @@
     }
 
     private static boolean isPrivilegedApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
 
     private static boolean isSystemApp(ApplicationInfo info) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 696aa34..8ea0bee 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,10 +32,10 @@
     PackageSetting(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
-            int pVersionCode, int pkgFlags) {
+            int pVersionCode, int pkgFlags, int privateFlags) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags);
+                pVersionCode, pkgFlags, privateFlags);
     }
 
     /**
@@ -62,6 +62,6 @@
     }
 
     public boolean isPrivileged() {
-        return (pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 1dcadb4..4b8ca42 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -112,8 +112,8 @@
     PackageSettingBase(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
-            int pVersionCode, int pkgFlags) {
-        super(pkgFlags);
+            int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
+        super(pkgFlags, pkgPrivateFlags);
         this.name = name;
         this.realName = realName;
         init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
index 5d30e76..bb0dba1 100644
--- a/services/core/java/com/android/server/pm/PendingPackage.java
+++ b/services/core/java/com/android/server/pm/PendingPackage.java
@@ -24,10 +24,10 @@
     PendingPackage(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString, int sharedId,
-            int pVersionCode, int pkgFlags) {
+            int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags);
+                pVersionCode, pkgFlags, pkgPrivateFlags);
         this.sharedId = sharedId;
     }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 524f638..d353494 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -281,11 +281,11 @@
     PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
-            int pkgFlags, UserHandle user, boolean add) {
+            int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add) {
         final String name = pkg.packageName;
         PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
                 resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
-                pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);
+                pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user, add, true /* allowInstall */);
         return p;
     }
 
@@ -311,13 +311,13 @@
     }
 
     SharedUserSetting getSharedUserLPw(String name,
-            int pkgFlags, boolean create) {
+            int pkgFlags, int pkgPrivateFlags, boolean create) {
         SharedUserSetting s = mSharedUsers.get(name);
         if (s == null) {
             if (!create) {
                 return null;
             }
-            s = new SharedUserSetting(name, pkgFlags);
+            s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
             s.userId = newUserIdLPw(s);
             Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
             // < 0 means we couldn't assign a userid; fall out and return
@@ -373,7 +373,7 @@
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.secondaryCpuAbiString,
-                p.appId, p.versionCode, p.pkgFlags);
+                p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -388,7 +388,7 @@
 
     PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
-            String cpuAbiOverrideString, int uid, int vc, int pkgFlags) {
+            String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.appId == uid) {
@@ -400,7 +400,7 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath,
                 legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                cpuAbiOverrideString, vc, pkgFlags);
+                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags);
         p.appId = uid;
         if (addUserIdLPw(uid, p, name)) {
             mPackages.put(name, p);
@@ -409,7 +409,7 @@
         return null;
     }
 
-    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
+    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
         SharedUserSetting s = mSharedUsers.get(name);
         if (s != null) {
             if (s.userId == uid) {
@@ -419,7 +419,7 @@
                     "Adding duplicate shared user, keeping first: " + name);
             return null;
         }
-        s = new SharedUserSetting(name, pkgFlags);
+        s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
         s.userId = uid;
         if (addUserIdLPw(uid, s, name)) {
             mSharedUsers.put(name, s);
@@ -469,7 +469,7 @@
     private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
-            int vc, int pkgFlags, UserHandle installUser, boolean add,
+            int vc, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean add,
             boolean allowInstall) {
         PackageSetting p = mPackages.get(name);
         UserManagerService userManager = UserManagerService.getInstance();
@@ -511,9 +511,8 @@
                 // If what we are scanning is a system (and possibly privileged) package,
                 // then make it so, regardless of whether it was previously installed only
                 // in the data partition.
-                final int sysPrivFlags = pkgFlags
-                        & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
-                p.pkgFlags |= sysPrivFlags;
+                p.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+                p.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             }
         }
         if (p == null) {
@@ -521,7 +520,7 @@
                 // We are consuming the data from an existing package.
                 p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
                         legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                        null /* cpuAbiOverrideString */, vc, pkgFlags);
+                        null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
                 if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                         + name + " is adopting original package " + origPackage.name);
                 // Note that we will retain the new package's signature so
@@ -539,7 +538,7 @@
             } else {
                 p = new PackageSetting(name, realName, codePath, resourcePath,
                         legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                        null /* cpuAbiOverrideString */, vc, pkgFlags);
+                        null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
                 p.setTimeStamp(codePath.lastModified());
                 p.sharedUser = sharedUser;
                 // If this is not a system app, it starts out stopped.
@@ -1818,7 +1817,8 @@
             serializer.attribute(null, "cpuAbiOverride", pkg.cpuAbiOverrideString);
         }
 
-        serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
+        serializer.attribute(null, "publicFlags", Integer.toString(pkg.pkgFlags));
+        serializer.attribute(null, "privateFlags", Integer.toString(pkg.pkgPrivateFlags));
         serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
         serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
         serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
@@ -2127,8 +2127,8 @@
                 PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
                         (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
                         pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,
-                        pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, null,
-                        true /* add */, false /* allowInstall */);
+                        pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, pp.pkgPrivateFlags,
+                        null, true /* add */, false /* allowInstall */);
                 if (p == null) {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unable to create application package for " + pp.name);
@@ -2596,14 +2596,15 @@
         }
 
         int pkgFlags = 0;
+        int pkgPrivateFlags = 0;
         pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
         final File codePathFile = new File(codePathStr);
         if (PackageManagerService.locationIsPrivileged(codePathFile)) {
-            pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+            pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         }
         PackageSetting ps = new PackageSetting(name, realName, codePathFile,
                 new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
-                secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags);
+                secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags);
         String timeStampStr = parser.getAttributeValue(null, "ft");
         if (timeStampStr != null) {
             try {
@@ -2662,6 +2663,11 @@
         mDisabledSysPackages.put(name, ps);
     }
 
+    private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27;
+    private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
+    private static int PRE_M_APP_INFO_FLAG_FORWARD_LOCK = 1<<29;
+    private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
+
     private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
         String name = null;
         String realName = null;
@@ -2678,6 +2684,7 @@
         String installerPackageName = null;
         String uidError = null;
         int pkgFlags = 0;
+        int pkgPrivateFlags = 0;
         long timeStamp = 0;
         long firstInstallTime = 0;
         long lastUpdateTime = 0;
@@ -2713,22 +2720,54 @@
             }
             installerPackageName = parser.getAttributeValue(null, "installer");
 
-            systemStr = parser.getAttributeValue(null, "flags");
+            systemStr = parser.getAttributeValue(null, "publicFlags");
             if (systemStr != null) {
                 try {
                     pkgFlags = Integer.parseInt(systemStr);
                 } catch (NumberFormatException e) {
                 }
-            } else {
-                // For backward compatibility
-                systemStr = parser.getAttributeValue(null, "system");
+                systemStr = parser.getAttributeValue(null, "privateFlags");
                 if (systemStr != null) {
-                    pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
-                            : 0;
+                    try {
+                        pkgPrivateFlags = Integer.parseInt(systemStr);
+                    } catch (NumberFormatException e) {
+                    }
+                }
+            } else {
+                // Pre-M -- both public and private flags were stored in one "flags" field.
+                systemStr = parser.getAttributeValue(null, "flags");
+                if (systemStr != null) {
+                    try {
+                        pkgFlags = Integer.parseInt(systemStr);
+                    } catch (NumberFormatException e) {
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_HIDDEN) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_FORWARD_LOCK) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_PRIVILEGED) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+                    }
+                    pkgFlags &= ~(PRE_M_APP_INFO_FLAG_HIDDEN
+                            | PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE
+                            | PRE_M_APP_INFO_FLAG_FORWARD_LOCK
+                            | PRE_M_APP_INFO_FLAG_PRIVILEGED);
                 } else {
-                    // Old settings that don't specify system... just treat
-                    // them as system, good enough.
-                    pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+                    // For backward compatibility
+                    systemStr = parser.getAttributeValue(null, "system");
+                    if (systemStr != null) {
+                        pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+                                : 0;
+                    } else {
+                        // Old settings that don't specify system... just treat
+                        // them as system, good enough.
+                        pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+                    }
                 }
             }
             String timeStampStr = parser.getAttributeValue(null, "ft");
@@ -2781,7 +2820,8 @@
             } else if (userId > 0) {
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                         new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
-                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags);
+                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
+                        pkgPrivateFlags);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
                             + userId + " pkg=" + packageSetting);
@@ -2800,7 +2840,7 @@
                     packageSetting = new PendingPackage(name.intern(), realName, new File(
                             codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                             primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                            userId, versionCode, pkgFlags);
+                            userId, versionCode, pkgFlags, pkgPrivateFlags);
                     packageSetting.setTimeStamp(timeStamp);
                     packageSetting.firstInstallTime = firstInstallTime;
                     packageSetting.lastUpdateTime = lastUpdateTime;
@@ -2967,6 +3007,7 @@
         String name = null;
         String idStr = null;
         int pkgFlags = 0;
+        int pkgPrivateFlags = 0;
         SharedUserSetting su = null;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
@@ -2985,7 +3026,8 @@
                                 + " has bad userId " + idStr + " at "
                                 + parser.getPositionDescription());
             } else {
-                if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
+                if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
+                        == null) {
                     PackageManagerService
                             .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
                                     + parser.getPositionDescription());
@@ -3302,9 +3344,12 @@
         ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
         ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
         ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
-        ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
-        ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
-        ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+    };
+
+    static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
+        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+        ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
     };
 
     void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, PackageSetting ps,
@@ -3391,6 +3436,8 @@
                 pw.println(ps.pkg.applicationInfo.toString());
             pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
                     FLAG_DUMP_SPEC); pw.println();
+            pw.print(prefix); pw.print("  priavateFlags="); printFlags(pw,
+                    ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
             pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
             if (ps.pkg.mOperationPending) {
                 pw.print(prefix); pw.println("  mOperationPending=true");
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2b406f7..d95739c 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -28,14 +28,16 @@
 
     // flags that are associated with this uid, regardless of any package flags
     int uidFlags;
+    int uidPrivateFlags;
 
     final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
 
     final PackageSignatures signatures = new PackageSignatures();
 
-    SharedUserSetting(String _name, int _pkgFlags) {
-        super(_pkgFlags);
+    SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
+        super(_pkgFlags, _pkgPrivateFlags);
         uidFlags =  _pkgFlags;
+        uidPrivateFlags = _pkgPrivateFlags;
         name = _name;
     }
 
@@ -55,12 +57,20 @@
                 }
                 setFlags(aggregatedFlags);
             }
+            if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
+                int aggregatedPrivateFlags = uidPrivateFlags;
+                for (PackageSetting ps : packages) {
+                    aggregatedPrivateFlags |= ps.pkgPrivateFlags;
+                }
+                setPrivateFlags(aggregatedPrivateFlags);
+            }
         }
     }
 
     void addPackage(PackageSetting packageSetting) {
         if (packages.add(packageSetting)) {
             setFlags(this.pkgFlags | packageSetting.pkgFlags);
+            setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f85b195..69a1ac9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1592,7 +1592,8 @@
                 try {
                     for (ApplicationInfo appInfo : apps) {
                         if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
-                                && (appInfo.flags & ApplicationInfo.FLAG_HIDDEN) != 0) {
+                                && (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN)
+                                        != 0) {
                             mPm.setApplicationHiddenSettingAsUser(appInfo.packageName, false,
                                     userHandle);
                         }
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/services/core/java/com/android/server/policy/BarController.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/BarController.java
rename to services/core/java/com/android/server/policy/BarController.java
index bfbd60d..bca2c16 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.app.StatusBarManager;
 import android.os.Handler;
diff --git a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
rename to services/core/java/com/android/server/policy/EnableAccessibilityController.java
index 6f79f58..da9c001 100644
--- a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
+++ b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.ActivityManager;
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
similarity index 97%
rename from policy/src/com/android/internal/policy/impl/GlobalActions.java
rename to services/core/java/com/android/server/policy/GlobalActions.java
index b0b2886..d768fe3 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import com.android.internal.app.AlertController;
 import com.android.internal.app.AlertController.AlertParams;
@@ -67,7 +67,6 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
 import android.view.WindowManagerPolicy.WindowManagerFuncs;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
@@ -100,6 +99,7 @@
     private static final String GLOBAL_ACTION_KEY_USERS = "users";
     private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
     private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+    private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
 
     private final Context mContext;
     private final WindowManagerFuncs mWindowManagerFuncs;
@@ -291,6 +291,8 @@
                 mItems.add(getSettingsAction());
             } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
                 mItems.add(getLockdownAction());
+            } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
+                mItems.add(getVoiceAssistAction());
             } else {
                 Log.e(TAG, "Invalid global action key " + actionKey);
             }
@@ -436,6 +438,28 @@
         };
     }
 
+    private Action getVoiceAssistAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search,
+                R.string.global_action_voice_assist) {
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
     private Action getLockdownAction() {
         return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
                 R.string.global_action_lockdown) {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
rename to services/core/java/com/android/server/policy/GlobalKeyManager.java
index fc65793..e08c004 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/services/core/java/com/android/server/policy/IconUtilities.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/IconUtilities.java
rename to services/core/java/com/android/server/policy/IconUtilities.java
index 82f26ad..4658344 100644
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ b/services/core/java/com/android/server/policy/IconUtilities.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
rename to services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 8fc4647..e511346 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.animation.ArgbEvaluator;
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -28,7 +27,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
diff --git a/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java b/services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
similarity index 96%
rename from policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
rename to services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
index 1f3e1de..ed5dc6f 100644
--- a/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
+++ b/services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.view.animation.Interpolator;
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
similarity index 97%
rename from policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
rename to services/core/java/com/android/server/policy/PhoneWindowManager.java
index d4032cc..5bb193a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -43,6 +43,7 @@
 import android.graphics.Rect;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -88,6 +89,7 @@
 import android.view.KeyCharacterMap.FallbackAction;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -103,12 +105,11 @@
 import android.view.animation.AnimationUtils;
 
 import com.android.internal.R;
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate;
-import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.PointerLocationView;
 import com.android.server.LocalServices;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate.ShowListener;
 
 import java.io.File;
 import java.io.FileReader;
@@ -153,6 +154,7 @@
     static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3;
+    static final int SHORT_PRESS_POWER_GO_HOME = 4;
 
     static final int LONG_PRESS_POWER_NOTHING = 0;
     static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
@@ -376,6 +378,8 @@
     int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mHasSoftInput = false;
     boolean mTranslucentDecorEnabled = true;
+    boolean mUseTvRouting;
+    boolean mUseMasterVolume;
 
     int mPointerLocationMode = 0; // guarded by mLock
 
@@ -971,6 +975,9 @@
                             PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
                     launchHomeFromHotKey();
                     break;
+                case SHORT_PRESS_POWER_GO_HOME:
+                    launchHomeFromHotKey();
+                    break;
             }
         }
     }
@@ -1188,8 +1195,7 @@
         } catch (RemoteException ex) { }
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
-        mShortcutManager = new ShortcutManager(context, mHandler);
-        mShortcutManager.observe();
+        mShortcutManager = new ShortcutManager(context);
         mUiMode = context.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultUiModeType);
         mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
@@ -1262,6 +1268,10 @@
         mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_triplePressOnPowerBehavior);
 
+        mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
+        mUseMasterVolume = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useMasterVolume);
+
         readConfigurationDependentBehaviors();
 
         mAccessibilityManager = (AccessibilityManager) context.getSystemService(
@@ -2030,7 +2040,7 @@
                 }
             }
 
-            Window win = PolicyManager.makeNewWindow(context);
+            Window win = new PhoneWindow(context);
             final TypedArray ta = win.getWindowStyle();
             if (ta.getBoolean(
                         com.android.internal.R.styleable.Window_windowDisablePreview, false)
@@ -2982,7 +2992,7 @@
                         } catch (RemoteException e) {
                         }
                         sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                        startDockOrHome();
+                        startDockOrHome(true /*fromHomeKey*/);
                     }
                 }
             });
@@ -3000,7 +3010,7 @@
             } else {
                 // Otherwise, just launch Home
                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                startDockOrHome();
+                startDockOrHome(true /*fromHomeKey*/);
             }
         }
     }
@@ -4534,6 +4544,10 @@
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                if (mUseTvRouting) {
+                    // On TVs volume keys never go to the foreground app
+                    result &= ~ACTION_PASS_TO_USER;
+                }
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
                         if (interactive && !mScreenshotChordVolumeDownKeyTriggered
@@ -4595,11 +4609,15 @@
                     }
 
                     if ((result & ACTION_PASS_TO_USER) == 0) {
-                        // If we aren't passing to the user and no one else
-                        // handled it send it to the session manager to figure
-                        // out.
-                        MediaSessionLegacyHelper.getHelper(mContext)
-                                .sendVolumeKeyEvent(event, true);
+                        if (mUseTvRouting) {
+                            dispatchDirectAudioEvent(event);
+                        } else {
+                            // If we aren't passing to the user and no one else
+                            // handled it send it to the session manager to
+                            // figure out.
+                            MediaSessionLegacyHelper.getHelper(mContext)
+                                    .sendVolumeKeyEvent(event, true);
+                        }
                         break;
                     }
                 }
@@ -4844,6 +4862,59 @@
         return false;
     }
 
+    private void dispatchDirectAudioEvent(KeyEvent event) {
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return;
+        }
+        int keyCode = event.getKeyCode();
+        int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND;
+        String pkgName = mContext.getOpPackageName();
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_UP:
+                try {
+                    if (mUseMasterVolume) {
+                        getAudioService().adjustMasterVolume(AudioManager.ADJUST_RAISE, flags,
+                                pkgName);
+                    } else {
+                        getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
+                                AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
+                }
+                break;
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+                try {
+                    if (mUseMasterVolume) {
+                        getAudioService().adjustMasterVolume(AudioManager.ADJUST_LOWER, flags,
+                                pkgName);
+                    } else {
+                        getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
+                                AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
+                }
+                break;
+            case KeyEvent.KEYCODE_VOLUME_MUTE:
+                try {
+                    if (event.getRepeatCount() == 0) {
+                        if (mUseMasterVolume) {
+                            getAudioService().adjustMasterVolume(AudioManager.ADJUST_TOGGLE_MUTE,
+                                    flags, pkgName);
+                        } else {
+                            getAudioService().adjustSuggestedStreamVolume(
+                                    AudioManager.ADJUST_TOGGLE_MUTE,
+                                    AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
+                }
+                break;
+        }
+    }
+
     void dispatchMediaKeyWithWakeLock(KeyEvent event) {
         if (DEBUG_INPUT) {
             Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
@@ -5261,20 +5332,11 @@
     }
 
     void sendCloseSystemWindows() {
-        sendCloseSystemWindows(mContext, null);
+        PhoneWindow.sendCloseSystemWindows(mContext, null);
     }
 
     void sendCloseSystemWindows(String reason) {
-        sendCloseSystemWindows(mContext, reason);
-    }
-
-    static void sendCloseSystemWindows(Context context, String reason) {
-        if (ActivityManagerNative.isSystemReady()) {
-            try {
-                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
-            } catch (RemoteException e) {
-            }
-        }
+        PhoneWindow.sendCloseSystemWindows(mContext, reason);
     }
 
     @Override
@@ -5811,19 +5873,31 @@
         return null;
     }
 
-    void startDockOrHome() {
+    void startDockOrHome(boolean fromHomeKey) {
         awakenDreams();
 
         Intent dock = createHomeDockIntent();
         if (dock != null) {
             try {
+                if (fromHomeKey) {
+                    dock.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
+                }
                 mContext.startActivityAsUser(dock, UserHandle.CURRENT);
                 return;
             } catch (ActivityNotFoundException e) {
             }
         }
 
-        mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
+        Intent intent;
+
+        if (fromHomeKey) {
+            intent = new Intent(mHomeIntent);
+            intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
+        } else {
+            intent = mHomeIntent;
+        }
+
+        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
     }
 
     /**
@@ -5838,7 +5912,7 @@
             } catch (RemoteException e) {
             }
             sendCloseSystemWindows();
-            startDockOrHome();
+            startDockOrHome(false /*fromHomeKey*/);
         } else {
             // This code brings home to the front or, if it is already
             // at the front, puts the device to sleep.
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/PolicyControl.java
rename to services/core/java/com/android/server/policy/PolicyControl.java
index 9abd906..dbafc42 100644
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.app.ActivityManager;
 import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java
rename to services/core/java/com/android/server/policy/RecentApplicationsBackground.java
index 3490bd4..694a110 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java
+++ b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.content.Context;
 import android.graphics.Canvas;
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
new file mode 100644
index 0000000..76f56bc
--- /dev/null
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyCharacterMap;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Manages quick launch shortcuts by:
+ * <li> Keeping the local copy in sync with the database (this is an observer)
+ * <li> Returning a shortcut-matching intent to clients
+ */
+class ShortcutManager {
+    private static final String TAG = "ShortcutManager";
+
+    private static final String TAG_BOOKMARKS = "bookmarks";
+    private static final String TAG_BOOKMARK = "bookmark";
+
+    private static final String ATTRIBUTE_PACKAGE = "package";
+    private static final String ATTRIBUTE_CLASS = "class";
+    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+    private static final String ATTRIBUTE_CATEGORY = "category";
+
+    private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
+
+    private final Context mContext;
+    
+    public ShortcutManager(Context context) {
+        mContext = context;
+        loadShortcuts();
+    }
+
+    /**
+     * Gets the shortcut intent for a given keycode+modifier. Make sure you
+     * strip whatever modifier is used for invoking shortcuts (for example,
+     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
+     * 'Sym' bit from the modifiers before calling this method.
+     * <p>
+     * This will first try an exact match (with modifiers), and then try a
+     * match without modifiers (primary character on a key).
+     * 
+     * @param kcm The key character map of the device on which the key was pressed.
+     * @param keyCode The key code.
+     * @param metaState The meta state, omitting any modifiers that were used
+     * to invoke the shortcut.
+     * @return The intent that matches the shortcut, or null if not found.
+     */
+    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
+        ShortcutInfo shortcut = null;
+
+        // First try the exact keycode (with modifiers).
+        int shortcutChar = kcm.get(keyCode, metaState);
+        if (shortcutChar != 0) {
+            shortcut = mShortcuts.get(shortcutChar);
+        }
+
+        // Next try the primary character on that key.
+        if (shortcut == null) {
+            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+            if (shortcutChar != 0) {
+                shortcut = mShortcuts.get(shortcutChar);
+            }
+        }
+
+        return (shortcut != null) ? shortcut.intent : null;
+    }
+
+    private void loadShortcuts() {
+        PackageManager packageManager = mContext.getPackageManager();
+        try {
+            XmlResourceParser parser = mContext.getResources().getXml(
+                    com.android.internal.R.xml.bookmarks);
+            XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                if (!TAG_BOOKMARK.equals(parser.getName())) {
+                    break;
+                }
+
+                String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
+                String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
+                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
+                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+
+                if (TextUtils.isEmpty(shortcutName)) {
+                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
+                    continue;
+                }
+
+                final int shortcutChar = shortcutName.charAt(0);
+
+                final Intent intent;
+                final String title;
+                if (packageName != null && className != null) {
+                    ActivityInfo info = null;
+                    ComponentName componentName = new ComponentName(packageName, className);
+                    try {
+                        info = packageManager.getActivityInfo(componentName, 0);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        String[] packages = packageManager.canonicalToCurrentPackageNames(
+                                new String[] { packageName });
+                        componentName = new ComponentName(packages[0], className);
+                        try {
+                            info = packageManager.getActivityInfo(componentName, 0);
+                        } catch (PackageManager.NameNotFoundException e1) {
+                            Log.w(TAG, "Unable to add bookmark: " + packageName
+                                    + "/" + className, e);
+                            continue;
+                        }
+                    }
+
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
+                    intent.setComponent(componentName);
+                    title = info.loadLabel(packageManager).toString();
+                } else if (categoryName != null) {
+                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+                    title = "";
+                } else {
+                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
+                            + ": missing package/class or category attributes");
+                    continue;
+                }
+
+                ShortcutInfo shortcut = new ShortcutInfo(title, intent);
+                mShortcuts.put(shortcutChar, shortcut);
+            }
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        } catch (IOException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        }
+    }
+
+    private static final class ShortcutInfo {
+        public final String title;
+        public final Intent intent;
+
+        public ShortcutInfo(String title, Intent intent) {
+            this.title = title;
+            this.intent = intent;
+        }
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
rename to services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 4ff9315..cfa631f 100644
--- a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.content.Context;
 import android.util.Slog;
diff --git a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java b/services/core/java/com/android/server/policy/WakeGestureListener.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/WakeGestureListener.java
rename to services/core/java/com/android/server/policy/WakeGestureListener.java
index 9396c2c..1d5d7ba 100644
--- a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java
+++ b/services/core/java/com/android/server/policy/WakeGestureListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.os.Handler;
 import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
rename to services/core/java/com/android/server/policy/WindowOrientationListener.java
index 2f60d55..0118127 100644
--- a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl;
+package com.android.server.policy;
 
 import android.content.Context;
 import android.hardware.Sensor;
@@ -25,7 +25,6 @@
 import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Slog;
-import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
similarity index 99%
rename from policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
rename to services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 6e8f550..c3fc195 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,4 +1,4 @@
-package com.android.internal.policy.impl.keyguard;
+package com.android.server.policy.keyguard;
 
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
similarity index 98%
rename from policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
rename to services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index b3b7684..2dc685b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl.keyguard;
+package com.android.server.policy.keyguard;
 
 import android.content.Context;
 import android.os.Bundle;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
similarity index 97%
rename from policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java
rename to services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 6f9c617..926090e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy.impl.keyguard;
+package com.android.server.policy.keyguard;
 
 import android.app.ActivityManager;
 import android.content.Context;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 5d73149..c677e2c 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -26,6 +26,7 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TypedValue;
+
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
@@ -83,11 +84,23 @@
     // Contains configurations settings that are different from the global configuration due to
     // stack specific operations. E.g. {@link #setBounds}.
     Configuration mOverrideConfig;
+    // True if the stack was forced to fullscreen disregarding the override configuration.
+    private boolean mForceFullscreen;
+    // The {@link #mBounds} before the stack was forced to fullscreen. Will be restored as the
+    // stack bounds once the stack is no longer forced to fullscreen.
+    final private Rect mPreForceFullscreenBounds;
+
+    // When true this stack is at the top of the screen and should be layed out to extend under
+    // the status bar.
+    boolean mUnderStatusBar;
 
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
         mOverrideConfig = Configuration.EMPTY;
+        mForceFullscreen = false;
+        mPreForceFullscreenBounds = new Rect();
+        mUnderStatusBar = true;
         // TODO: remove bounds from log, they are always 0.
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
                 mBounds.right, mBounds.bottom);
@@ -102,8 +115,6 @@
     }
 
     void resizeWindows() {
-        final boolean underStatusBar = mBounds.top == 0;
-
         final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
@@ -116,19 +127,29 @@
                                 "setBounds: Resizing " + win);
                         resizingWindows.add(win);
                     }
-                    win.mUnderStatusBar = underStatusBar;
                 }
             }
         }
     }
 
+    /** Set the stack bounds. Passing in null sets the bounds to fullscreen. */
     boolean setBounds(Rect bounds) {
         boolean oldFullscreen = mFullscreen;
         if (mDisplayContent != null) {
             mDisplayContent.getLogicalDisplayRect(mTmpRect);
-            mFullscreen = mTmpRect.equals(bounds);
+            if (bounds == null) {
+                bounds = mTmpRect;
+                mFullscreen = true;
+            } else {
+                bounds.intersect(mTmpRect); // ensure bounds are entirely within the display rect
+                mFullscreen = mTmpRect.equals(bounds);
+            }
         }
 
+        if (bounds == null) {
+            // Can set to fullscreen if we don't have a display to get bounds from...
+            return false;
+        }
         if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) {
             return false;
         }
@@ -136,6 +157,7 @@
         mDimLayer.setBounds(bounds);
         mAnimationBackgroundSurface.setBounds(bounds);
         mBounds.set(bounds);
+        mUnderStatusBar = (mBounds.top == 0);
         updateOverrideConfiguration();
         return true;
     }
@@ -144,7 +166,7 @@
         out.set(mBounds);
     }
 
-    void updateOverrideConfiguration() {
+    private void updateOverrideConfiguration() {
         final Configuration serviceConfig = mService.mCurConfiguration;
         if (mFullscreen) {
             mOverrideConfig = Configuration.EMPTY;
@@ -163,6 +185,9 @@
                 Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
         mOverrideConfig.smallestScreenWidthDp =
                 Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+        mOverrideConfig.orientation =
+                (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+                        ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
     }
 
     void updateDisplayInfo() {
@@ -176,6 +201,28 @@
         return mFullscreen;
     }
 
+    /** Forces the stack to fullscreen if input is true, else un-forces the stack from fullscreen.
+     * Returns true if something happened.
+     */
+    boolean forceFullscreen(boolean forceFullscreen) {
+        if (mForceFullscreen == forceFullscreen) {
+            return false;
+        }
+        mForceFullscreen = forceFullscreen;
+        if (forceFullscreen) {
+            if (mFullscreen) {
+                return false;
+            }
+            mPreForceFullscreenBounds.set(mBounds);
+            return setBounds(null);
+        } else {
+            if (!mFullscreen || mPreForceFullscreenBounds.isEmpty()) {
+                return false;
+            }
+            return setBounds(mPreForceFullscreenBounds);
+        }
+    }
+
     boolean isAnimating() {
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 3987132..abf8412 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -146,35 +146,6 @@
         mDisplayContentsAnimators.delete(displayId);
     }
 
-    void hideWallpapersLocked(final WindowState w) {
-        final WindowState wallpaperTarget = mService.mWallpaperTarget;
-        final WindowState lowerWallpaperTarget = mService.mLowerWallpaperTarget;
-        final ArrayList<WindowToken> wallpaperTokens = mService.mWallpaperTokens;
-
-        if ((wallpaperTarget == w && lowerWallpaperTarget == null) || wallpaperTarget == null) {
-            final int numTokens = wallpaperTokens.size();
-            for (int i = numTokens - 1; i >= 0; i--) {
-                final WindowToken token = wallpaperTokens.get(i);
-                final int numWindows = token.windows.size();
-                for (int j = numWindows - 1; j >= 0; j--) {
-                    final WindowState wallpaper = token.windows.get(j);
-                    final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
-                    if (!winAnimator.mLastHidden) {
-                        winAnimator.hide();
-                        mService.dispatchWallpaperVisibility(wallpaper, false);
-                        setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
-                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
-                    }
-                }
-                if (WindowManagerService.DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG,
-                        "Hiding wallpaper " + token + " from " + w
-                        + " target=" + wallpaperTarget + " lower=" + lowerWallpaperTarget
-                        + "\n" + Debug.getCallers(5, "  "));
-                token.hidden = true;
-            }
-        }
-    }
-
     private void updateAppWindowsLocked(int displayId) {
         ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -791,6 +762,7 @@
             } else if (dumpAll) {
                 pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
             }
+            pw.println();
         }
 
         pw.println();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 66bef41..02a4f4d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -29,8 +29,6 @@
 import android.view.IWindowSessionCallback;
 import android.view.WindowContentFrameStats;
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.PhoneWindowManager;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -45,6 +43,7 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.input.InputManagerService;
 import com.android.server.power.ShutdownThread;
+import com.android.server.policy.PhoneWindowManager;
 
 import android.Manifest;
 import android.app.ActivityManagerNative;
@@ -284,12 +283,6 @@
     // The name of the boot animation service in init.rc.
     private static final String BOOT_ANIMATION_SERVICE = "bootanim";
 
-    /** Minimum value for attachStack and resizeStack weight value */
-    public static final float STACK_WEIGHT_MIN = 0.2f;
-
-    /** Maximum value for attachStack and resizeStack weight value */
-    public static final float STACK_WEIGHT_MAX = 0.8f;
-
     static final int UPDATE_FOCUS_NORMAL = 0;
     static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
     static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
@@ -344,7 +337,7 @@
 
     final boolean mLimitedAlphaCompositing;
 
-    final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
+    final WindowManagerPolicy mPolicy = new PhoneWindowManager();
 
     final IActivityManager mActivityManager;
 
@@ -589,7 +582,7 @@
         }
     }
 
-    final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+    private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
 
     // If non-null, this is the currently visible window that is associated
     // with the wallpaper.
@@ -1701,7 +1694,7 @@
         return true;
     }
 
-    final boolean isWallpaperVisible(WindowState wallpaperTarget) {
+    private boolean isWallpaperVisible(WindowState wallpaperTarget) {
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
                 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
@@ -1715,6 +1708,34 @@
                 || mLowerWallpaperTarget != null;
     }
 
+    void hideWallpapersLocked(final WindowState winGoingAway) {
+        if (mWallpaperTarget != null &&
+                (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
+            return;
+        }
+
+        for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+            final WindowToken token = mWallpaperTokens.get(i);
+            for (int j = token.windows.size() - 1; j >= 0; j--) {
+                final WindowState wallpaper = token.windows.get(j);
+                final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+                if (!winAnimator.mLastHidden) {
+                    winAnimator.hide();
+                    dispatchWallpaperVisibility(wallpaper, false);
+                    final DisplayContent displayContent = wallpaper.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.pendingLayoutChanges |=
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                }
+            }
+            if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
+                    + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
+                    + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
+            token.hidden = true;
+        }
+    }
+
     static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
     static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
 
@@ -1897,7 +1918,7 @@
             // AND any starting window associated with it, AND below the
             // maximum layer the policy allows for wallpapers.
             while (foundI > 0) {
-                WindowState wb = windows.get(foundI-1);
+                WindowState wb = windows.get(foundI - 1);
                 if (wb.mBaseLayer < maxLayer &&
                         wb.mAttachedWindow != foundW &&
                         (foundW.mAttachedWindow == null ||
@@ -1923,7 +1944,7 @@
         } else {
             // Okay i is the position immediately above the wallpaper.  Look at
             // what is below it for later.
-            foundW = foundI > 0 ? windows.get(foundI-1) : null;
+            foundW = foundI > 0 ? windows.get(foundI - 1) : null;
         }
 
         if (visible) {
@@ -1946,43 +1967,37 @@
         // Start stepping backwards from here, ensuring that our wallpaper windows
         // are correctly placed.
         int changed = 0;
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowToken token = mWallpaperTokens.get(curTokenNdx);
             if (token.hidden == visible) {
                 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
                         "Wallpaper token " + token + " hidden=" + !visible);
                 changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED;
                 token.hidden = !visible;
-                // Need to do a layout to ensure the wallpaper now has the
-                // correct size.
+                // Need to do a layout to ensure the wallpaper now has the correct size.
                 getDefaultDisplayContentLocked().layoutNeeded = true;
             }
 
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+            final WindowList tokenWindows = token.windows;
+            for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = tokenWindows.get(wallpaperNdx);
 
                 if (visible) {
                     updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
 
-                // First, make sure the client has the current visibility
-                // state.
+                // First, make sure the client has the current visibility state.
                 dispatchWallpaperVisibility(wallpaper, visible);
 
-                wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+                wallpaper.mWinAnimator.mAnimLayer =
+                        wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
                 if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
 
-                // First, if this window is at the current index, then all
-                // is well.
+                // First, if this window is at the current index, then all is well.
                 if (wallpaper == foundW) {
                     foundI--;
-                    foundW = foundI > 0
-                            ? windows.get(foundI-1) : null;
+                    foundW = foundI > 0 ? windows.get(foundI - 1) : null;
                     continue;
                 }
 
@@ -2022,48 +2037,20 @@
             }
         }
 
-        /*
-        final TaskStack targetStack =
-                mWallpaperTarget == null ? null : mWallpaperTarget.getStack();
-        if ((changed & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0 &&
-                targetStack != null && !targetStack.isHomeStack()) {
-            // If the wallpaper target is not on the home stack then make sure that all windows
-            // from other non-home stacks are above the wallpaper.
-            for (i = foundI - 1; i >= 0; --i) {
-                WindowState win = windows.get(i);
-                if (!win.isVisibleLw()) {
-                    continue;
-                }
-                final TaskStack winStack = win.getStack();
-                if (winStack != null && !winStack.isHomeStack() && winStack != targetStack) {
-                    windows.remove(i);
-                    windows.add(foundI + 1, win);
-                }
-            }
-        }
-        */
-
-        if (targetChanged && DEBUG_WALLPAPER_LIGHT) {
-            Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
-                    + " lower=" + mLowerWallpaperTarget + " upper="
-                    + mUpperWallpaperTarget);
-        }
+        if (targetChanged && DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target="
+                + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
+                + mUpperWallpaperTarget);
 
         return changed;
     }
 
     void setWallpaperAnimLayerAdjustmentLocked(int adj) {
-        if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG,
-                "Setting wallpaper layer adj to " + adj);
+        if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
         mWallpaperAnimLayerAdjustment = adj;
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+            for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = windows.get(wallpaperNdx);
                 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
                 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
@@ -2197,14 +2184,10 @@
             }
         }
 
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+            for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = windows.get(wallpaperNdx);
                 if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
                     WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
                     winAnimator.computeShownFrameLocked();
@@ -2236,7 +2219,7 @@
         }
     }
 
-    void updateWallpaperVisibilityLocked() {
+    private void updateWallpaperVisibilityLocked() {
         final boolean visible = isWallpaperVisible(mWallpaperTarget);
         final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
         if (displayContent == null) {
@@ -2246,21 +2229,18 @@
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
 
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowToken token = mWallpaperTokens.get(curTokenNdx);
             if (token.hidden == visible) {
                 token.hidden = !visible;
                 // Need to do a layout to ensure the wallpaper now has the
                 // correct size.
-                getDefaultDisplayContentLocked().layoutNeeded = true;
+                displayContent.layoutNeeded = true;
             }
 
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+            final WindowList windows = token.windows;
+            for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = windows.get(wallpaperNdx);
                 if (visible) {
                     updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
@@ -2918,14 +2898,10 @@
         if (window == mWallpaperTarget || window == mLowerWallpaperTarget
                 || window == mUpperWallpaperTarget) {
             boolean doWait = sync;
-            int curTokenIndex = mWallpaperTokens.size();
-            while (curTokenIndex > 0) {
-                curTokenIndex--;
-                WindowToken token = mWallpaperTokens.get(curTokenIndex);
-                int curWallpaperIndex = token.windows.size();
-                while (curWallpaperIndex > 0) {
-                    curWallpaperIndex--;
-                    WindowState wallpaper = token.windows.get(curWallpaperIndex);
+            for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+                final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+                for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                    WindowState wallpaper = windows.get(wallpaperNdx);
                     try {
                         wallpaper.mClient.dispatchWallpaperCommand(action,
                                 x, y, z, extras, sync);
@@ -3563,13 +3539,13 @@
                                 false /*updateInputWindows*/);
                     }
 
-                    if (delayed) {
-                        if (displayContent != null) {
-                            displayContent.mExitingTokens.add(wtoken);
-                        }
+                    if (delayed && displayContent != null) {
+                        displayContent.mExitingTokens.add(wtoken);
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
+                } else if (wtoken.windowType == TYPE_WALLPAPER) {
+                    mWallpaperTokens.remove(wtoken);
                 }
 
                 mInputMonitor.updateInputWindowsLw(true /*force*/);
@@ -5123,6 +5099,26 @@
         bounds.setEmpty();
     }
 
+    /** Forces the stack to fullscreen if input is true, else un-forces the stack from fullscreen.
+     * Returns a {@link Configuration} object that contains configurations settings
+     * that should be overridden due to the operation.
+     */
+    public Configuration forceStackToFullscreen(int stackId, boolean forceFullscreen) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("resizeStack: stackId " + stackId
+                        + " not found.");
+            }
+            if (stack.forceFullscreen(forceFullscreen)) {
+                stack.resizeWindows();
+                stack.getDisplayContent().layoutNeeded = true;
+                performLayoutAndPlaceSurfacesLocked();
+            }
+            return new Configuration(stack.mOverrideConfig);
+        }
+    }
+
     // -------------------------------------------------------------
     // Misc IWindowSession methods
     // -------------------------------------------------------------
@@ -9570,9 +9566,6 @@
                     // it is animating.
                     displayContent.pendingLayoutChanges = 0;
 
-                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
-                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
-
                     if (isDefaultDisplay) {
                         mPolicy.beginPostLayoutPolicyLw(dw, dh);
                         for (i = windows.size() - 1; i >= 0; i--) {
@@ -9656,7 +9649,7 @@
                     if (w.mHasSurface && !w.isHiddenFromUserLocked()) {
                         // Take care of the window being ready to display.
                         final boolean committed =
-                                winAnimator.commitFinishDrawingLocked(currentTime);
+                                winAnimator.commitFinishDrawingLocked();
                         if (isDefaultDisplay && committed) {
                             if (w.mAttrs.type == TYPE_DREAM) {
                                 // HACK: When a dream is shown, it may at that
@@ -10513,15 +10506,13 @@
                 scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
-                screenRotationAnimation = null;
-                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
+                mAnimator.setScreenRotationAnimationLocked(displayId, null);
                 updateRotation = true;
             }
         } else {
             if (screenRotationAnimation != null) {
                 screenRotationAnimation.kill();
-                screenRotationAnimation = null;
-                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
+                mAnimator.setScreenRotationAnimationLocked(displayId, null);
             }
             updateRotation = true;
         }
@@ -10788,7 +10779,7 @@
 
     void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
         pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
-        if (mTokenMap.size() > 0) {
+        if (!mTokenMap.isEmpty()) {
             pw.println("  All tokens:");
             Iterator<WindowToken> it = mTokenMap.values().iterator();
             while (it.hasNext()) {
@@ -10802,7 +10793,7 @@
                 }
             }
         }
-        if (mWallpaperTokens.size() > 0) {
+        if (!mWallpaperTokens.isEmpty()) {
             pw.println();
             pw.println("  Wallpaper tokens:");
             for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
@@ -10817,7 +10808,7 @@
                 }
             }
         }
-        if (mFinishedStarting.size() > 0) {
+        if (!mFinishedStarting.isEmpty()) {
             pw.println();
             pw.println("  Finishing start of application tokens:");
             for (int i=mFinishedStarting.size()-1; i>=0; i--) {
@@ -10832,7 +10823,7 @@
                 }
             }
         }
-        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
+        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
             pw.println();
             if (mOpeningApps.size() > 0) {
                 pw.print("  mOpeningApps="); pw.println(mOpeningApps);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 98f00de..e88dace 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -232,7 +232,8 @@
 
     final Rect mParentFrame = new Rect();
 
-    // The entire screen area of the device.
+    // The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
+    // screen area of the device.
     final Rect mDisplayFrame = new Rect();
 
     // The region of the display frame that the display type supports displaying content on. This
@@ -342,10 +343,6 @@
     /** When true this window can be displayed on screens owther than mOwnerUid's */
     private boolean mShowToOwnerOnly;
 
-    /** When true this window is at the top of the screen and should be layed out to extend under
-     * the status bar */
-    boolean mUnderStatusBar = true;
-
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, final DisplayContent displayContent) {
@@ -509,16 +506,16 @@
 
         TaskStack stack = mAppToken != null ? getStack() : null;
         if (stack != null && !stack.isFullscreen()) {
-            getStackBounds(stack, mContainingFrame);
-            if (mUnderStatusBar) {
+            stack.getBounds(mContainingFrame);
+            if (stack.mUnderStatusBar) {
                 mContainingFrame.top = pf.top;
             }
+            mDisplayFrame.set(mContainingFrame);
         } else {
             mContainingFrame.set(pf);
+            mDisplayFrame.set(df);
         }
 
-        mDisplayFrame.set(df);
-
         final int pw = mContainingFrame.width();
         final int ph = mContainingFrame.height();
 
@@ -576,9 +573,6 @@
         final int fw = mFrame.width();
         final int fh = mFrame.height();
 
-        //System.out.println("In: w=" + w + " h=" + h + " container=" +
-        //                   container + " x=" + mAttrs.x + " y=" + mAttrs.y);
-
         float x, y;
         if (mEnforceSizeCompat) {
             x = mAttrs.x * mGlobalScale;
@@ -588,14 +582,15 @@
             y = mAttrs.y;
         }
 
+        // Make sure window fits in containing frame required by {@link Gravity#apply} call.
+        w = Math.min(w, pw);
+        h = Math.min(h, ph);
         Gravity.apply(mAttrs.gravity, w, h, mContainingFrame,
                 (int) (x + mAttrs.horizontalMargin * pw),
                 (int) (y + mAttrs.verticalMargin * ph), mFrame);
 
-        //System.out.println("Out: " + mFrame);
-
-        // Now make sure the window fits in the overall display.
-        Gravity.applyDisplay(mAttrs.gravity, df, mFrame);
+        // Now make sure the window fits in the overall display frame.
+        Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
 
         // Make sure the content and visible frames are inside of the
         // final window frame.
@@ -808,10 +803,7 @@
     }
 
     void getStackBounds(Rect bounds) {
-        getStackBounds(getStack(), bounds);
-    }
-
-    private void getStackBounds(TaskStack stack, Rect bounds) {
+        final TaskStack stack = getStack();
         if (stack != null) {
             stack.getBounds(bounds);
             return;
@@ -1471,7 +1463,11 @@
     }
 
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        final TaskStack stack = getStack();
         pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
+                if (stack != null) {
+                    pw.print(" stackId="); pw.print(stack.mStackId);
+                }
                 pw.print(" mSession="); pw.print(mSession);
                 pw.print(" mClient="); pw.println(mClient.asBinder());
         pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 8202880..a78bab4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -53,21 +53,16 @@
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
-import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
-import com.android.internal.R;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-class WinAnimatorList extends ArrayList<WindowStateAnimator> {
-}
-
 /**
  * Keep track of animations and surface operations for a single WindowState.
  **/
@@ -185,7 +180,7 @@
 
     int mAttrType;
 
-    public WindowStateAnimator(final WindowState win) {
+    WindowStateAnimator(final WindowState win) {
         final WindowManagerService service = win.mService;
 
         mService = service;
@@ -482,7 +477,7 @@
             mService.mPendingRemove.add(mWin);
             mWin.mRemoveOnExit = false;
         }
-        mAnimator.hideWallpapersLocked(mWin);
+        mService.hideWallpapersLocked(mWin);
     }
 
     void hide() {
@@ -523,7 +518,7 @@
     }
 
     // This must be called while inside a transaction.
-    boolean commitFinishDrawingLocked(long currentTime) {
+    boolean commitFinishDrawingLocked() {
         if (DEBUG_STARTING_WINDOW &&
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
             Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
@@ -538,9 +533,9 @@
         mDrawState = READY_TO_SHOW;
         final AppWindowToken atoken = mWin.mAppToken;
         if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
-            performShowLocked();
+            return performShowLocked();
         }
-        return true;
+        return false;
     }
 
     static class SurfaceTrace extends SurfaceControl {
@@ -980,7 +975,7 @@
                     }
                     mSurfaceControl.destroy();
                 }
-                mAnimator.hideWallpapersLocked(mWin);
+                mService.hideWallpapersLocked(mWin);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Exception thrown when destroying Window " + this
                     + " surface " + mSurfaceControl + " session " + mSession
@@ -1006,7 +1001,7 @@
                     WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
                 }
                 mPendingDestroySurface.destroy();
-                mAnimator.hideWallpapersLocked(mWin);
+                mService.hideWallpapersLocked(mWin);
             }
         } catch (RuntimeException e) {
             Slog.w(TAG, "Exception thrown when destroying Window "
@@ -1454,7 +1449,7 @@
             hide();
         } else if (w.mAttachedHidden || !w.isOnScreen()) {
             hide();
-            mAnimator.hideWallpapersLocked(w);
+            mService.hideWallpapersLocked(w);
 
             // If we are waiting for this window to handle an
             // orientation change, well, it is hidden, so
@@ -1626,13 +1621,8 @@
         }
         if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
-            RuntimeException e = null;
-            if (!WindowManagerService.HIDE_STACK_CRAWLS) {
-                e = new RuntimeException();
-                e.fillInStackTrace();
-            }
             Slog.v(TAG, "performShow on " + this
-                    + ": mDrawState=" + mDrawState + " readyForDisplay="
+                    + ": mDrawState=" + drawStateToString() + " readyForDisplay="
                     + mWin.isReadyForDisplayIgnoringKeyguard()
                     + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING)
                     + " during animation: policyVis=" + mWin.mPolicyVisibility
@@ -1643,7 +1633,8 @@
                     + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
                     + " animating=" + mAnimating
                     + " tok animating="
-                    + (mAppAnimator != null ? mAppAnimator.animating : false), e);
+                    + (mAppAnimator != null ? mAppAnimator.animating : false) + " Callers="
+                    + Debug.getCallers(3));
         }
         if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplayIgnoringKeyguard()) {
             if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e4d0b77..fbb6f7c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1914,12 +1914,12 @@
         }
     }
 
-    public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
+    public void setPasswordQuality(ComponentName who, int quality) {
         if (!mHasFeature) {
             return;
         }
+        final int userHandle = UserHandle.getCallingUserId();
         validateQualityConstant(quality);
-        enforceCrossUserPermission(userHandle);
 
         synchronized (this) {
             if (who == null) {
@@ -1963,11 +1963,11 @@
         }
     }
 
-    public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumLength(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2010,11 +2010,11 @@
         }
     }
 
-    public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+    public void setPasswordHistoryLength(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2057,11 +2057,11 @@
         }
     }
 
-    public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+    public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2226,11 +2226,11 @@
         }
     }
 
-    public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumUpperCase(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2273,8 +2273,8 @@
         }
     }
 
-    public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
-        enforceCrossUserPermission(userHandle);
+    public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2317,11 +2317,11 @@
         }
     }
 
-    public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumLetters(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2364,11 +2364,11 @@
         }
     }
 
-    public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumNumeric(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2411,11 +2411,11 @@
         }
     }
 
-    public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumSymbols(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2458,11 +2458,11 @@
         }
     }
 
-    public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumNonLetter(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2522,8 +2522,7 @@
 
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
                     || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
                 return false;
@@ -2556,11 +2555,11 @@
         }
     }
 
-    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -2632,11 +2631,11 @@
         return strictestAdmin;
     }
 
-    public boolean resetPassword(String passwordOrNull, int flags, int userHandle) {
+    public boolean resetPassword(String passwordOrNull, int flags) {
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "reset the password");
 
         String password = passwordOrNull != null ? passwordOrNull : "";
@@ -2767,11 +2766,11 @@
         return true;
     }
 
-    public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -3050,7 +3049,10 @@
             mHandler.post(new Runnable() {
                 public void run() {
                     try {
-                        ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
+                        IActivityManager am = ActivityManagerNative.getDefault();
+                        if (am.getCurrentUser().id == userHandle) {
+                            am.switchUser(UserHandle.USER_OWNER);
+                        }
                         if (!mUserManager.removeUser(userHandle)) {
                             Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
                         }
@@ -3231,11 +3233,10 @@
     }
 
     public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
-            String exclusionList, int userHandle) {
+            String exclusionList) {
         if (!mHasFeature) {
             return null;
         }
-        enforceCrossUserPermission(userHandle);
         synchronized(this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -3261,7 +3262,7 @@
             // If the user is not the owner, don't set the global proxy. Fail silently.
             if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
                 Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
-                        + userHandle + " is not permitted.");
+                        + UserHandle.getCallingUserId() + " is not permitted.");
                 return null;
             }
             if (proxySpec == null) {
@@ -3371,11 +3372,11 @@
      * Set the storage encryption request for a single admin.  Returns the new total request
      * status (for all admins).
      */
-    public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+    public int setStorageEncryption(ComponentName who, boolean encrypt) {
         if (!mHasFeature) {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             // Check for permissions
             if (who == null) {
@@ -3507,11 +3508,11 @@
     /**
      * Set whether the screen capture is disabled for the user managed by the specified admin.
      */
-    public void setScreenCaptureDisabled(ComponentName who, int userHandle, boolean disabled) {
+    public void setScreenCaptureDisabled(ComponentName who, boolean disabled) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -3566,11 +3567,11 @@
     /**
      * Set whether auto time is required by the specified admin (must be device owner).
      */
-    public void setAutoTimeRequired(ComponentName who, int userHandle, boolean required) {
+    public void setAutoTimeRequired(ComponentName who, boolean required) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -3617,11 +3618,11 @@
     /**
      * Disables all device cameras according to the specified admin.
      */
-    public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+    public void setCameraDisabled(ComponentName who, boolean disabled) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -3666,11 +3667,11 @@
     /**
      * Selectively disable keyguard features.
      */
-    public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
+    public void setKeyguardDisabledFeatures(ComponentName who, int which) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "disable keyguard features");
         synchronized (this) {
             if (who == null) {
@@ -3920,7 +3921,7 @@
         Bundle userRestrictions = mUserManager.getUserRestrictions();
         mUserManager.setUserRestrictions(new Bundle(), userHandle);
         if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
-            audioManager.setMasterMute(false);
+            audioManager.adjustMasterVolume(AudioManager.ADJUST_UNMUTE, 0);
         }
         if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
             audioManager.setMicrophoneMute(false);
@@ -4216,11 +4217,11 @@
     }
 
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent,
-            PersistableBundle args, int userHandle) {
+            PersistableBundle args) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "set trust agent configuration");
         synchronized (this) {
             if (admin == null) {
@@ -4841,7 +4842,8 @@
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
                         iAudioService.setMicrophoneMute(true, who.getPackageName());
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.setMasterMute(true, 0, who.getPackageName(), null);
+                        iAudioService.adjustMasterVolume(AudioManager.ADJUST_MUTE, 0,
+                                who.getPackageName());
                     }
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -4906,7 +4908,8 @@
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
                         iAudioService.setMicrophoneMute(false, who.getPackageName());
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.setMasterMute(false, 0, who.getPackageName(), null);
+                        iAudioService.adjustMasterVolume(AudioManager.ADJUST_UNMUTE, 0,
+                                who.getPackageName());
                     }
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -5042,15 +5045,14 @@
                 if (activitiesToEnable != null) {
                     for (ResolveInfo info : activitiesToEnable) {
                         if (info.activityInfo != null) {
-
-                            if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) {
-                                throw new IllegalArgumentException(
-                                        "Only system apps can be enabled this way.");
+                            String packageName = info.activityInfo.packageName;
+                            if (isSystemApp(pm, packageName, primaryUser.id)) {
+                                numberOfAppsInstalled++;
+                                pm.installExistingPackageAsUser(packageName, userId);
+                            } else {
+                                Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+                                        + " system app");
                             }
-
-
-                            numberOfAppsInstalled++;
-                            pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
                         }
                     }
                 }
@@ -5069,6 +5071,10 @@
             throws RemoteException {
         ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES,
                 userId);
+        if (appInfo == null) {
+            throw new IllegalArgumentException("The application " + packageName +
+                    " is not present on this device");
+        }
         return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
@@ -5361,8 +5367,6 @@
 
     @Override
     public void setMasterVolumeMuted(ComponentName who, boolean on) {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
@@ -5372,7 +5376,9 @@
             IAudioService iAudioService = IAudioService.Stub.asInterface(
                     ServiceManager.getService(Context.AUDIO_SERVICE));
             try{
-                iAudioService.setMasterMute(on, 0, who.getPackageName(), null);
+                iAudioService.adjustMasterVolume(
+                        on ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE, 0,
+                        who.getPackageName());
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Failed to setMasterMute", re);
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7f9af31..875d395 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,7 +29,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.media.AudioService;
 import android.media.tv.TvInputManager;
 import android.os.Build;
 import android.os.Environment;
@@ -60,6 +59,7 @@
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.audio.AudioService;
 import com.android.server.clipboard.ClipboardService;
 import com.android.server.content.ContentService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 01a044e..c6f6b85 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,12 +20,15 @@
 import android.alsa.AlsaDevicesParser;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbInterface;
 import android.media.AudioSystem;
 import android.media.IAudioService;
+import android.midi.MidiDeviceInfo;
 import android.os.FileObserver;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -34,6 +37,8 @@
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.server.audio.AudioService;
+
 import libcore.io.IoUtils;
 
 import java.io.File;
@@ -73,6 +78,9 @@
 
     private UsbAudioDevice mSelectedAudioDevice = null;
 
+    // UsbMidiDevice for USB peripheral mode (gadget) device
+    private UsbMidiDevice mPeripheralMidiDevice = null;
+
     private final class AlsaDevice {
         public static final int TYPE_UNKNOWN = 0;
         public static final int TYPE_PLAYBACK = 1;
@@ -173,15 +181,16 @@
                         " alsaDevice: " + alsaDevice);
             return;
         }
-        String params = ("card=" + alsaCard + ";device=" + alsaDevice);
 
+        String address = AudioService.makeAlsaAddressString(alsaCard, alsaDevice);
         try {
             // Playback Device
             if (audioDevice.mHasPlayback) {
                 int device = (audioDevice == mAccessoryAudioDevice ?
                         AudioSystem.DEVICE_OUT_USB_ACCESSORY :
                         AudioSystem.DEVICE_OUT_USB_DEVICE);
-                mAudioService.setWiredDeviceConnectionState(device, state, params);
+                mAudioService.setWiredDeviceConnectionState(
+                        device, state, address, audioDevice.mDeviceName);
             }
 
             // Capture Device
@@ -189,7 +198,8 @@
                int device = (audioDevice == mAccessoryAudioDevice ?
                         AudioSystem.DEVICE_IN_USB_ACCESSORY :
                         AudioSystem.DEVICE_IN_USB_DEVICE);
-                mAudioService.setWiredDeviceConnectionState(device, state, params);
+                mAudioService.setWiredDeviceConnectionState(
+                        device, state, address, audioDevice.mDeviceName);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
@@ -391,7 +401,17 @@
                 int device = mDevicesParser.getDefaultDeviceNum(addedCard);
                 AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI);
                 if (alsaDevice != null) {
-                    UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, usbDevice,
+                    Bundle properties = new Bundle();
+                    properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER,
+                            usbDevice.getManufacturerName());
+                    properties.putString(MidiDeviceInfo.PROPERTY_MODEL, usbDevice.getProductName());
+                    properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+                            usbDevice.getSerialNumber());
+                    properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
+                    properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice);
+                    properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
+
+                    UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
                             alsaDevice.mCard, alsaDevice.mDevice);
                     if (usbMidiDevice != null) {
                         mMidiDevices.put(usbDevice, usbMidiDevice);
@@ -410,17 +430,16 @@
         if (audioDevice != null) {
             if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
                 notifyDeviceState(audioDevice, false);
+                mSelectedAudioDevice = null;
+
+                // if there any external devices left, select one of them
+                selectDefaultDevice();
             }
         }
         UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice);
         if (usbMidiDevice != null) {
             IoUtils.closeQuietly(usbMidiDevice);
         }
-
-        mSelectedAudioDevice = null;
-
-        // if there any external devices left, select one of them
-        selectDefaultDevice();
     }
 
    /* package */ void setAccessoryAudioState(boolean enabled, int card, int device) {
@@ -437,6 +456,23 @@
         }
     }
 
+   /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
+        if (enabled) {
+            Bundle properties = new Bundle();
+            Resources r = mContext.getResources();
+            properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
+                    com.android.internal.R.string.usb_midi_peripheral_manufacturer_name));
+            properties.putString(MidiDeviceInfo.PROPERTY_MODEL, r.getString(
+                    com.android.internal.R.string.usb_midi_peripheral_model_name));
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
+            mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
+        } else if (mPeripheralMidiDevice != null) {
+            IoUtils.closeQuietly(mPeripheralMidiDevice);
+            mPeripheralMidiDevice = null;
+        }
+   }
+
     //
     // Devices List
     //
diff --git a/services/usb/java/com/android/server/usb/UsbAudioDevice.java b/services/usb/java/com/android/server/usb/UsbAudioDevice.java
index 069d917..bdd28e4 100644
--- a/services/usb/java/com/android/server/usb/UsbAudioDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAudioDevice.java
@@ -53,7 +53,6 @@
         sb.append("UsbAudioDevice: [card: " + mCard);
         sb.append(", device: " + mDevice);
         sb.append(", name: " + mDeviceName);
-        sb.append(", description: " + mDeviceDescription);
         sb.append(", hasPlayback: " + mHasPlayback);
         sb.append(", hasCapture: " + mHasCapture);
         sb.append(", class: 0x" + Integer.toHexString(mDeviceClass) + "]");
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index 1cf00d2..e489279 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -31,6 +31,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.util.Base64;
 import com.android.server.FgThread;
@@ -206,6 +208,12 @@
                     break;
 
                 case MESSAGE_ADB_CONFIRM: {
+                    if ("trigger_restart_min_framework".equals(
+                            SystemProperties.get("vold.decrypt"))) {
+                        Slog.d(TAG, "Deferring adb confirmation until after vold decrypt");
+                        sendResponse("NO");
+                        break;
+                    }
                     String key = (String)msg.obj;
                     String fingerprints = getFingerprints(key);
                     if ("".equals(fingerprints)) {
@@ -279,7 +287,7 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
             try {
-                mContext.startActivity(intent);
+                mContext.startActivityAsUser(intent, UserHandle.OWNER);
                 return true;
             } catch (ActivityNotFoundException e) {
                 Slog.e(TAG, "unable to start adb whitelist activity: " + componentName, e);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1426551..2fb6dbf 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -31,6 +31,7 @@
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
 import android.media.AudioManager;
+import android.midi.MidiDeviceInfo;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -85,6 +86,8 @@
             "/sys/class/android_usb/android0/f_rndis/ethaddr";
     private static final String AUDIO_SOURCE_PCM_PATH =
             "/sys/class/android_usb/android0/f_audio_source/pcm";
+    private static final String MIDI_ALSA_PATH =
+            "/sys/class/android_usb/android0/f_midi/alsa";
 
     private static final int MSG_UPDATE_STATE = 0;
     private static final int MSG_ENABLE_ADB = 1;
@@ -124,6 +127,7 @@
     private boolean mUseUsbNotification;
     private boolean mAdbEnabled;
     private boolean mAudioSourceEnabled;
+    private boolean mMidiEnabled;
     private Map<String, List<Pair<String, String>>> mOemModeMap;
     private String[] mAccessoryStrings;
     private UsbDebuggingManager mDebuggingManager;
@@ -618,6 +622,31 @@
             }
         }
 
+        private void updateMidiFunction() {
+            boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
+            if (enabled != mMidiEnabled) {
+                int card = -1;
+                int device = -1;
+
+                if (enabled) {
+                    Scanner scanner = null;
+                    try {
+                        scanner = new Scanner(new File(MIDI_ALSA_PATH));
+                        card = scanner.nextInt();
+                        device = scanner.nextInt();
+                    } catch (FileNotFoundException e) {
+                        Slog.e(TAG, "could not open MIDI PCM file", e);
+                    } finally {
+                        if (scanner != null) {
+                            scanner.close();
+                        }
+                    }
+                }
+                mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
+                mMidiEnabled = enabled;
+            }
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -636,6 +665,7 @@
                     if (mBootCompleted) {
                         updateUsbState();
                         updateAudioSourceFunction();
+                        updateMidiFunction();
                     }
                     break;
                 case MSG_ENABLE_ADB:
@@ -651,6 +681,7 @@
                     updateAdbNotification();
                     updateUsbState();
                     updateAudioSourceFunction();
+                    updateMidiFunction();
                     break;
                 case MSG_BOOT_COMPLETED:
                     mBootCompleted = true;
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 01b2df9..8d44905 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -17,13 +17,12 @@
 package com.android.server.usb;
 
 import android.content.Context;
-import android.hardware.usb.UsbDevice;
 import android.midi.MidiDeviceInfo;
 import android.midi.MidiDeviceServer;
 import android.midi.MidiManager;
+import android.midi.MidiPort;
 import android.midi.MidiReceiver;
 import android.midi.MidiSender;
-import android.midi.MidiUtils;
 import android.os.Bundle;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -45,10 +44,12 @@
 
     // for polling multiple FileDescriptors for MIDI events
     private final StructPollfd[] mPollFDs;
+    // streams for reading from ALSA driver
     private final FileInputStream[] mInputStreams;
+    // streams for writing to ALSA driver
     private final FileOutputStream[] mOutputStreams;
 
-    public static UsbMidiDevice create(Context context, UsbDevice usbDevice, int card, int device) {
+    public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
         MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
         if (midiManager == null) {
             Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
@@ -69,13 +70,6 @@
             return null;
         }
 
-        Bundle properties = new Bundle();
-        properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, usbDevice.getManufacturerName());
-        properties.putString(MidiDeviceInfo.PROPERTY_MODEL, usbDevice.getProductName());
-        properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER, usbDevice.getSerialNumber());
-        properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
-        properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
-        properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
         MidiDeviceServer server = midiManager.createDeviceServer(subDevices, subDevices, properties,
                 false, MidiDeviceInfo.TYPE_USB);
         if (server == null) {
@@ -131,7 +125,7 @@
         new Thread() {
             @Override
             public void run() {
-                byte[] buffer = new byte[3];
+                byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE];
                 try {
                     boolean done = false;
                     while (!done) {
@@ -141,7 +135,8 @@
                             if ((pfd.revents & OsConstants.POLLIN) != 0) {
                                 // clear readable flag
                                 pfd.revents = 0;
-                                int count = readMessage(buffer, index);
+
+                                int count = mInputStreams[index].read(buffer);
                                 mOutputPortReceivers[index].onPost(buffer, 0, count,
                                         System.nanoTime());
                             } else if ((pfd.revents & (OsConstants.POLLERR
@@ -150,7 +145,7 @@
                             }
                         }
 
-                        // poll if none are readable
+                        // wait until we have a readable port
                         Os.poll(mPollFDs, -1 /* infinite timeout */);
                      }
                 } catch (IOException e) {
@@ -174,26 +169,6 @@
         }
     }
 
-    private int readMessage(byte[] buffer, int index) throws IOException {
-        FileInputStream inputStream = mInputStreams[index];
-
-        if (inputStream.read(buffer, 0, 1) != 1) {
-            Log.e(TAG, "could not read command byte");
-            return -1;
-        }
-        int dataSize = MidiUtils.getMessageDataSize(buffer[0]);
-        if (dataSize < 0) {
-            return -1;
-        }
-        if (dataSize > 0) {
-            if (inputStream.read(buffer, 1, dataSize) != dataSize) {
-                Log.e(TAG, "could not read command data");
-                return -1;
-            }
-        }
-        return dataSize + 1;
-    }
-
     private static native int nativeGetSubdeviceCount(int card, int device);
     private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
 }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index a180f44..108c0af 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -260,6 +260,7 @@
         /** @hide */
         public void onConferenceParticipantsChanged(Connection c,
                 List<ConferenceParticipant> participants) {}
+        public void onConferenceStarted() {}
     }
 
     /** @hide */
@@ -1001,14 +1002,11 @@
     /**
      * Informs listeners that this {@code Connection} has processed a character in the post-dial
      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
-     * (b) it has encountered a "wait" character; and (c) it wishes to signal Telecom to play
-     * the corresponding DTMF tone locally.
+     * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
      *
      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
-     *
-     * @hide
      */
-    public final void setNextPostDialWaitChar(char nextChar) {
+    public final void setNextPostDialChar(char nextChar) {
         checkImmutable();
         for (Listener l : mListeners) {
             l.onPostDialChar(this, nextChar);
@@ -1422,4 +1420,13 @@
             l.onConferenceParticipantsChanged(this, conferenceParticipants);
         }
     }
+
+    /**
+     * Notifies listeners that a conference call has been started.
+     */
+    protected void notifyConferenceStarted() {
+        for (Listener l : mListeners) {
+            l.onConferenceStarted();
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 052a481..a94c2f6 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -40,15 +40,13 @@
 /**
  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
  * want those calls to be integrated into the dialer and in-call UI should build an instance of
- * this class and register it with the system using {@link TelecomManager#registerPhoneAccount}.
+ * this class and register it with the system using {@link TelecomManager}.
  * <p>
  * {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with
  * alternative options when placing a phone call. When building a {@link PhoneAccount}, the app
- * should supply a valid {@link PhoneAccountHandle} that references the {@link ConnectionService}
+ * should supply a valid {@link PhoneAccountHandle} that references the connection service
  * implementation Telecom will use to interact with the app.
- * @hide
  */
-@SystemApi
 public class PhoneAccount implements Parcelable {
 
     /**
@@ -62,7 +60,9 @@
      * if the user has explicitly selected it to be used as the default connection manager.
      * <p>
      * See {@link #getCapabilities}
+     * @hide
      */
+    @SystemApi
     public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
 
     /**
@@ -76,6 +76,7 @@
      * <p>
      * {@hide}
      */
+    @SystemApi
     public static final int CAPABILITY_CALL_PROVIDER = 0x2;
 
     /**
@@ -94,6 +95,7 @@
      * See {@link #getCapabilities}
      * @hide
      */
+    @SystemApi
     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
 
     /**
@@ -111,6 +113,7 @@
      * See {@link #getCapabilities}
      * @hide
      */
+    @SystemApi
     public static final int CAPABILITY_MULTI_USER = 0x20;
 
     /**
@@ -203,6 +206,7 @@
         }
 
         /** @hide */
+        @SystemApi
         public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
             mAccountHandle = accountHandle;
             return this;
@@ -333,6 +337,7 @@
          * @return The builder.
          * @hide
          */
+        @SystemApi
         public Builder addSupportedUriScheme(String uriScheme) {
             if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
                 this.mSupportedUriSchemes.add(uriScheme);
@@ -423,6 +428,7 @@
      * @return The builder.
      * @hide
      */
+    @SystemApi
     public Builder toBuilder() { return new Builder(this); }
 
     /**
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 97af41a..570f5fd 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -29,16 +29,13 @@
  * The unique identifier for a {@link PhoneAccount}. A {@code PhoneAccountHandle} is made of two
  * parts:
  * <ul>
- *  <li>The component name of the associated {@link ConnectionService}.</li>
+ *  <li>The component name of the associated connection service.</li>
  *  <li>A string identifier that is unique across {@code PhoneAccountHandle}s with the same
  *      component name.</li>
  * </ul>
  *
- * See {@link PhoneAccount},
- * {@link TelecomManager#registerPhoneAccount TelecomManager.registerPhoneAccount}.
- * @hide
+ * See {@link PhoneAccount}, {@link TelecomManager}.
  */
-@SystemApi
 public class PhoneAccountHandle implements Parcelable {
     private final ComponentName mComponentName;
     private final String mId;
@@ -51,6 +48,7 @@
     }
 
     /** @hide */
+    @SystemApi
     public PhoneAccountHandle(
             ComponentName componentName,
             String id,
@@ -61,8 +59,8 @@
     }
 
     /**
-     * The {@code ComponentName} of the {@link android.telecom.ConnectionService} which is
-     * responsible for making phone calls using this {@code PhoneAccountHandle}.
+     * The {@code ComponentName} of the connection service which is responsible for making phone
+     * calls using this {@code PhoneAccountHandle}.
      *
      * @return A suitable {@code ComponentName}.
      */
@@ -72,9 +70,9 @@
 
     /**
      * A string that uniquely distinguishes this particular {@code PhoneAccountHandle} from all the
-     * others supported by the {@link ConnectionService} that created it.
+     * others supported by the connection service that created it.
      * <p>
-     * A {@code ConnectionService} must select identifiers that are stable for the lifetime of
+     * A connection service must select identifiers that are stable for the lifetime of
      * their users' relationship with their service, across many Android devices. For example, a
      * good set of identifiers might be the email addresses with which with users registered for
      * their accounts with a particular service. Depending on how a service chooses to operate,
@@ -92,6 +90,7 @@
      * @return the {@link UserHandle} to use when connecting to this PhoneAccount.
      * @hide
      */
+    @SystemApi
     public UserHandle getUserHandle() {
         return mUserHandle;
     }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 073dcd5..a9b725b 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -60,11 +60,16 @@
                 mPendingConnections.remove(connection);
                 // Unconditionally initialize the connection ...
                 connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
-                connection.setAddress(
-                        parcel.getHandle(), parcel.getHandlePresentation());
-                connection.setCallerDisplayName(
-                        parcel.getCallerDisplayName(),
-                        parcel.getCallerDisplayNamePresentation());
+                if (parcel.getHandle() != null
+                    || parcel.getState() != Connection.STATE_DISCONNECTED) {
+                    connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
+                }
+                if (parcel.getCallerDisplayName() != null
+                    || parcel.getState() != Connection.STATE_DISCONNECTED) {
+                    connection.setCallerDisplayName(
+                            parcel.getCallerDisplayName(),
+                            parcel.getCallerDisplayNamePresentation());
+                }
                 // Set state after handle so that the client can identify the connection.
                 if (parcel.getState() == Connection.STATE_DISCONNECTED) {
                     connection.setDisconnected(parcel.getDisconnectCause());
@@ -235,8 +240,12 @@
 
         @Override
         public void setVideoProvider(String callId, IVideoProvider videoProvider) {
+            RemoteConnection.VideoProvider remoteVideoProvider = null;
+            if (videoProvider != null) {
+                remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+            }
             findConnectionForAction(callId, "setVideoProvider")
-                    .setVideoProvider(new RemoteConnection.VideoProvider(videoProvider));
+                    .setVideoProvider(remoteVideoProvider);
         }
 
         @Override
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 1a6b292..6c5f1c6 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -106,7 +106,6 @@
      * {@link VideoProfile.VideoState#BIDIRECTIONAL},
      * {@link VideoProfile.VideoState#RX_ENABLED},
      * {@link VideoProfile.VideoState#TX_ENABLED}.
-     * @hide
      */
     public static final String EXTRA_START_CALL_WITH_VIDEO_STATE =
             "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
@@ -117,9 +116,7 @@
      * {@link PhoneAccountHandle} to use when making the call.
      * <p class="note">
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
             "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
 
@@ -139,10 +136,7 @@
      * {@link android.content.Intent#ACTION_DIAL} {@code Intent} containing a {@link Bundle}
      * which contains metadata about the call. This {@link Bundle} will be saved into
      * {@code Call.Details}.
-     *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_OUTGOING_CALL_EXTRAS =
             "android.telecom.extra.OUTGOING_CALL_EXTRAS";
 
@@ -554,9 +548,7 @@
      *
      * @param account The {@link PhoneAccountHandle}.
      * @return The {@link PhoneAccount} object.
-     * @hide
      */
-    @SystemApi
     public PhoneAccount getPhoneAccount(PhoneAccountHandle account) {
         try {
             if (isServiceConnected()) {
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index f5cb054..e62e994 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -21,8 +21,6 @@
 
 /**
  * Represents attributes of video calls.
- *
- * {@hide}
  */
 public class VideoProfile implements Parcelable {
     /**
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index a59505c..69bb4bb 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -34,11 +34,9 @@
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
-import android.telephony.Rlog;
 import android.text.style.TtsSpan;
 import android.util.SparseIntArray;
 
-import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
@@ -1843,7 +1841,7 @@
         // to the list.
         number = extractNetworkPortionAlt(number);
 
-        Rlog.d(LOG_TAG, "subId:" + subId + ", number: " +  number + ", defaultCountryIso:" +
+        Rlog.d(LOG_TAG, "subId:" + subId + ", defaultCountryIso:" +
                 ((defaultCountryIso == null) ? "NULL" : defaultCountryIso));
 
         String emergencyNumbers = "";
@@ -2200,8 +2198,8 @@
         if (!TextUtils.isEmpty(dialStr)) {
             if (isReallyDialable(dialStr.charAt(0)) &&
                 isNonSeparator(dialStr)) {
-                String currIso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY, "");
-                String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
+                String currIso = TelephonyManager.getDefault().getNetworkCountryIso();
+                String defaultIso = TelephonyManager.getDefault().getSimCountryIso();
                 if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) {
                     return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
                             getFormatTypeFromCountryCode(currIso),
@@ -2223,7 +2221,7 @@
     public static String cdmaCheckAndProcessPlusCodeForSms(String dialStr) {
         if (!TextUtils.isEmpty(dialStr)) {
             if (isReallyDialable(dialStr.charAt(0)) && isNonSeparator(dialStr)) {
-                String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
+                String defaultIso = TelephonyManager.getDefault().getSimCountryIso();
                 if (!TextUtils.isEmpty(defaultIso)) {
                     int format = getFormatTypeFromCountryCode(defaultIso);
                     return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr, format, format);
@@ -2339,15 +2337,13 @@
      *
      * @param phoneNumber A {@code CharSequence} the entirety of which represents a phone number.
      * @return A {@code CharSequence} with appropriate annotations.
-     *
-     * @hide
      */
-    public static CharSequence ttsSpanAsPhoneNumber(CharSequence phoneNumber) {
+    public static CharSequence getPhoneTtsSpannable(CharSequence phoneNumber) {
         if (phoneNumber == null) {
             return null;
         }
         Spannable spannable = Spannable.Factory.getInstance().newSpannable(phoneNumber);
-        PhoneNumberUtils.ttsSpanAsPhoneNumber(spannable, 0, spannable.length());
+        PhoneNumberUtils.addPhoneTtsSpan(spannable, 0, spannable.length());
         return spannable;
     }
 
@@ -2358,19 +2354,83 @@
      * @param s A {@code Spannable} to annotate.
      * @param start The starting character position of the phone number in {@code s}.
      * @param end The ending character position of the phone number in {@code s}.
-     *
-     * @hide
      */
-    public static void ttsSpanAsPhoneNumber(Spannable s, int start, int end) {
-        s.setSpan(
-                new TtsSpan.TelephoneBuilder()
-                        .setNumberParts(splitAtNonNumerics(s.subSequence(start, end)))
-                        .build(),
+    public static void addPhoneTtsSpan(Spannable s, int start, int end) {
+        s.setSpan(getPhoneTtsSpan(s.subSequence(start, end).toString()),
                 start,
                 end,
                 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
+    /**
+     * Wrap the supplied {@code CharSequence} with a {@code TtsSpan}, annotating it as
+     * containing a phone number in its entirety.
+     *
+     * @param phoneNumber A {@code CharSequence} the entirety of which represents a phone number.
+     * @return A {@code CharSequence} with appropriate annotations.
+     * @deprecated Renamed {@link #getPhoneTtsSpannable}.
+     *
+     * @hide
+     */
+    @Deprecated
+    public static CharSequence ttsSpanAsPhoneNumber(CharSequence phoneNumber) {
+        return getPhoneTtsSpannable(phoneNumber);
+    }
+
+    /**
+     * Attach a {@link TtsSpan} to the supplied {@code Spannable} at the indicated location,
+     * annotating that location as containing a phone number.
+     *
+     * @param s A {@code Spannable} to annotate.
+     * @param start The starting character position of the phone number in {@code s}.
+     * @param end The ending character position of the phone number in {@code s}.
+     *
+     * @deprecated Renamed {@link #addPhoneTtsSpan}.
+     *
+     * @hide
+     */
+    @Deprecated
+    public static void ttsSpanAsPhoneNumber(Spannable s, int start, int end) {
+        addPhoneTtsSpan(s, start, end);
+    }
+
+    /**
+     * Create a {@code TtsSpan} for the supplied {@code String}.
+     *
+     * @param phoneNumberString A {@code String} the entirety of which represents a phone number.
+     * @return A {@code TtsSpan} for {@param phoneNumberString}.
+     */
+    public static TtsSpan getPhoneTtsSpan(String phoneNumberString) {
+        if (phoneNumberString == null) {
+            return null;
+        }
+
+        // Parse the phone number
+        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+        PhoneNumber phoneNumber = null;
+        try {
+            // Don't supply a defaultRegion so this fails for non-international numbers because
+            // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
+            // present
+            phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
+        } catch (NumberParseException ignored) {
+        }
+
+        // Build a telephone tts span
+        final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
+        if (phoneNumber == null) {
+            // Strip separators otherwise TalkBack will be silent
+            // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
+            builder.setNumberParts(splitAtNonNumerics(phoneNumberString));
+        } else {
+            if (phoneNumber.hasCountryCode()) {
+                builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
+            }
+            builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
+        }
+        return builder.build();
+    }
+
     // Split a phone number like "+20(123)-456#" using spaces, ignoring anything that is not
     // a digit, to produce a result like "20 123 456".
     private static String splitAtNonNumerics(CharSequence number) {
@@ -2388,11 +2448,11 @@
 
     private static String getCurrentIdp(boolean useNanp) {
         String ps = null;
-        if(useNanp)
+        if (useNanp) {
             ps = NANP_IDP_STRING;
-        else{
+        } else {
             // in case, there is no IDD is found, we shouldn't convert it.
-            ps = SystemProperties.get(PROPERTY_OPERATOR_IDP_STRING, PLUS_SIGN_STRING);                
+            ps = SystemProperties.get(PROPERTY_OPERATOR_IDP_STRING, PLUS_SIGN_STRING);
         }
         return ps;
     }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index adbe1d8..ca3c636 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -335,7 +335,7 @@
     public String toString() {
         return "{id=" + mId + ", iccId=" + mIccId + " simSlotIndex=" + mSimSlotIndex
                 + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
-                + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " number=" + mNumber
+                + " nameSource=" + mNameSource + " iconTint=" + mIconTint
                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
                 + " mnc " + mMnc + "}";
     }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index c67629d..aca94e9 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1101,9 +1101,7 @@
             // What else can we do?
             return false;
         }
-        // FIXME: use better way to get roaming status instead of reading from system property
-        return Boolean.parseBoolean(TelephonyManager.getTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null));
+        return TelephonyManager.getDefault().isNetworkRoaming(subId);
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ace945d..94691c0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -640,13 +640,9 @@
      */
     /** {@hide} */
     public String getDeviceId(int slotId) {
-        // FIXME methods taking slot id should not use subscription, instead us Uicc directly
-        int[] subId = SubscriptionManager.getSubId(slotId);
-        if (subId == null || subId.length == 0) {
-            return null;
-        }
+        // FIXME this assumes phoneId == slotId
         try {
-            return getSubscriberInfo().getDeviceIdForSubscriber(subId[0]);
+            return getSubscriberInfo().getDeviceIdForPhone(slotId);
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -703,7 +699,11 @@
     public String getNai(int slotId) {
         int[] subId = SubscriptionManager.getSubId(slotId);
         try {
-            return getSubscriberInfo().getNaiForSubscriber(subId[0]);
+            String nai = getSubscriberInfo().getNaiForSubscriber(subId[0]);
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Rlog.v(TAG, "Nai = " + nai);
+            }
+            return nai;
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1077,7 +1077,7 @@
      * on a CDMA network).
      */
     public String getNetworkOperator() {
-        return getNetworkOperator(getDefaultSubscription());
+        return getNetworkOperatorForPhone(getDefaultPhone());
     }
 
     /**
@@ -1091,8 +1091,23 @@
      * @param subId
      */
     /** {@hide} */
-   public String getNetworkOperator(int subId) {
+   public String getNetworkOperatorForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
+        return getNetworkOperatorForPhone(phoneId);
+     }
+
+    /**
+     * Returns the numeric name (MCC+MNC) of current registered operator
+     * for a particular subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     *
+     * @param phoneId
+     * @hide
+     **/
+   public String getNetworkOperatorForPhone(int phoneId) {
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
      }
 
@@ -1130,7 +1145,7 @@
      * on a CDMA network).
      */
     public String getNetworkCountryIso() {
-        return getNetworkCountryIso(getDefaultSubscription());
+        return getNetworkCountryIsoForPhone(getDefaultPhone());
     }
 
     /**
@@ -1144,8 +1159,23 @@
      * @param subId for which Network CountryIso is returned
      */
     /** {@hide} */
-    public String getNetworkCountryIso(int subId) {
+    public String getNetworkCountryIsoForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
+        return getNetworkCountryIsoForPhone(phoneId);
+    }
+
+    /**
+     * Returns the ISO country code equivalent of the current registered
+     * operator's MCC (Mobile Country Code) of a subscription.
+     * <p>
+     * Availability: Only when user is registered to a network. Result may be
+     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+     * on a CDMA network).
+     *
+     * @param phoneId for which Network CountryIso is returned
+     */
+    /** {@hide} */
+    public String getNetworkCountryIsoForPhone(int phoneId) {
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
     }
 
@@ -1537,6 +1567,34 @@
      * @see #getSimState
      */
     public String getSimOperator() {
+        return getSimOperatorNumeric();
+    }
+
+    /**
+     * Returns the MCC+MNC (mobile country code + mobile network code) of the
+     * provider of the SIM. 5 or 6 decimal digits.
+     * <p>
+     * Availability: SIM state must be {@link #SIM_STATE_READY}
+     *
+     * @see #getSimState
+     *
+     * @param subId for which SimOperator is returned
+     * @hide
+     */
+    public String getSimOperator(int subId) {
+        return getSimOperatorNumericForSubscription(subId);
+    }
+
+    /**
+     * Returns the MCC+MNC (mobile country code + mobile network code) of the
+     * provider of the SIM. 5 or 6 decimal digits.
+     * <p>
+     * Availability: SIM state must be {@link #SIM_STATE_READY}
+     *
+     * @see #getSimState
+     * @hide
+     */
+    public String getSimOperatorNumeric() {
         int subId = SubscriptionManager.getDefaultDataSubId();
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
             subId = SubscriptionManager.getDefaultSmsSubId();
@@ -1547,8 +1605,8 @@
                 }
             }
         }
-        Rlog.d(TAG, "getSimOperator(): default subId=" + subId);
-        return getSimOperator(subId);
+        Rlog.d(TAG, "getSimOperatorNumeric(): default subId=" + subId);
+        return getSimOperatorNumericForSubscription(subId);
     }
 
     /**
@@ -1560,14 +1618,24 @@
      * @see #getSimState
      *
      * @param subId for which SimOperator is returned
+     * @hide
      */
-    /** {@hide} */
-    public String getSimOperator(int subId) {
+    public String getSimOperatorNumericForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        String operator = getTelephonyProperty(phoneId,
+        return getSimOperatorNumericForPhone(phoneId);
+    }
+
+   /**
+     * Returns the MCC+MNC (mobile country code + mobile network code) of the
+     * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
+     * <p>
+     *
+     * @param phoneId for which SimOperator is returned
+     * @hide
+     */
+    public String getSimOperatorNumericForPhone(int phoneId) {
+        return getTelephonyProperty(phoneId,
                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
-        Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator);
-        return operator;
     }
 
     /**
@@ -1578,7 +1646,7 @@
      * @see #getSimState
      */
     public String getSimOperatorName() {
-        return getSimOperatorName(getDefaultSubscription());
+        return getSimOperatorNameForPhone(getDefaultPhone());
     }
 
     /**
@@ -1589,30 +1657,61 @@
      * @see #getSimState
      *
      * @param subId for which SimOperatorName is returned
+     * @hide
      */
-    /** {@hide} */
-    public String getSimOperatorName(int subId) {
+    public String getSimOperatorNameForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "");
+        return getSimOperatorNameForPhone(phoneId);
+    }
+
+    /**
+     * Returns the Service Provider Name (SPN).
+     *
+     * @hide
+     */
+    public String getSimOperatorNameForPhone(int phoneId) {
+         return getTelephonyProperty(phoneId,
+                TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "");
     }
 
     /**
      * Returns the ISO country code equivalent for the SIM provider's country code.
      */
     public String getSimCountryIso() {
-        return getSimCountryIso(getDefaultSubscription());
+        return getSimCountryIsoForPhone(getDefaultPhone());
     }
 
     /**
      * Returns the ISO country code equivalent for the SIM provider's country code.
      *
      * @param subId for which SimCountryIso is returned
+     *
+     * @hide
      */
-    /** {@hide} */
     public String getSimCountryIso(int subId) {
+        return getSimCountryIsoForSubscription(subId);
+    }
+
+    /**
+     * Returns the ISO country code equivalent for the SIM provider's country code.
+     *
+     * @param subId for which SimCountryIso is returned
+     *
+     * @hide
+     */
+    public String getSimCountryIsoForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
-                "");
+        return getSimCountryIsoForPhone(phoneId);
+    }
+
+    /**
+     * Returns the ISO country code equivalent for the SIM provider's country code.
+     *
+     * @hide
+     */
+    public String getSimCountryIsoForPhone(int phoneId) {
+        return getTelephonyProperty(phoneId,
+                TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
     }
 
     /**
@@ -3566,12 +3665,12 @@
     /** @hide */
     @SystemApi
     public boolean getDataEnabled(int subId) {
-        boolean retVal;
+        boolean retVal = false;
         try {
             retVal = getITelephony().getDataEnabled(subId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
-            retVal = false;
+        } catch (NullPointerException e) {
         }
         Log.d(TAG, "getDataEnabled: retVal=" + retVal);
         return retVal;
@@ -3677,4 +3776,344 @@
            return false;
        }
    }
+
+   /**
+    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
+    *
+    * @hide
+    */
+    public void setSimOperatorNumeric(String numeric) {
+        int phoneId = getDefaultPhone();
+        setSimOperatorNumericForPhone(phoneId, numeric);
+    }
+
+   /**
+    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the given phone.
+    *
+    * @hide
+    */
+    public void setSimOperatorNumericForPhone(int phoneId, String numeric) {
+        setTelephonyProperty(phoneId,
+                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, numeric);
+    }
+
+    /**
+     * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
+     *
+     * @hide
+     */
+    public void setSimOperatorName(String name) {
+        int phoneId = getDefaultPhone();
+        setSimOperatorNameForPhone(phoneId, name);
+    }
+
+    /**
+     * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the given phone.
+     *
+     * @hide
+     */
+    public void setSimOperatorNameForPhone(int phoneId, String name) {
+        setTelephonyProperty(phoneId,
+                TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, name);
+    }
+
+   /**
+    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY for the default phone.
+    *
+    * @hide
+    */
+    public void setSimCountryIso(String iso) {
+        int phoneId = getDefaultPhone();
+        setSimCountryIsoForPhone(phoneId, iso);
+    }
+
+   /**
+    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY for the given phone.
+    *
+    * @hide
+    */
+    public void setSimCountryIsoForPhone(int phoneId, String iso) {
+        setTelephonyProperty(phoneId,
+                TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
+    }
+
+    /**
+     * Set TelephonyProperties.PROPERTY_SIM_STATE for the default phone.
+     *
+     * @hide
+     */
+    public void setSimState(String state) {
+        int phoneId = getDefaultPhone();
+        setSimStateForPhone(phoneId, state);
+    }
+
+    /**
+     * Set TelephonyProperties.PROPERTY_SIM_STATE for the given phone.
+     *
+     * @hide
+     */
+    public void setSimStateForPhone(int phoneId, String state) {
+        setTelephonyProperty(phoneId,
+                TelephonyProperties.PROPERTY_SIM_STATE, state);
+    }
+
+    /**
+     * Set baseband version for the default phone.
+     *
+     * @param version baseband version
+     * @hide
+     */
+    public void setBasebandVersion(String version) {
+        int phoneId = getDefaultPhone();
+        setBasebandVersionForPhone(phoneId, version);
+    }
+
+    /**
+     * Set baseband version by phone id.
+     *
+     * @param phoneId for which baseband version is set
+     * @param version baseband version
+     * @hide
+     */
+    public void setBasebandVersionForPhone(int phoneId, String version) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            String prop = TelephonyProperties.PROPERTY_BASEBAND_VERSION +
+                    ((phoneId == 0) ? "" : Integer.toString(phoneId));
+            SystemProperties.set(prop, version);
+        }
+    }
+
+    /**
+     * Set phone type for the default phone.
+     *
+     * @param type phone type
+     *
+     * @hide
+     */
+    public void setPhoneType(int type) {
+        int phoneId = getDefaultPhone();
+        setPhoneType(phoneId, type);
+    }
+
+    /**
+     * Set phone type by phone id.
+     *
+     * @param phoneId for which phone type is set
+     * @param type phone type
+     *
+     * @hide
+     */
+    public void setPhoneType(int phoneId, int type) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            TelephonyManager.setTelephonyProperty(phoneId,
+                    TelephonyProperties.CURRENT_ACTIVE_PHONE, String.valueOf(type));
+        }
+    }
+
+    /**
+     * Get OTASP number schema for the default phone.
+     *
+     * @param defaultValue default value
+     * @return OTA SP number schema
+     *
+     * @hide
+     */
+    public String getOtaSpNumberSchema(String defaultValue) {
+        int phoneId = getDefaultPhone();
+        return getOtaSpNumberSchemaForPhone(phoneId, defaultValue);
+    }
+
+    /**
+     * Get OTASP number schema by phone id.
+     *
+     * @param phoneId for which OTA SP number schema is get
+     * @param defaultValue default value
+     * @return OTA SP number schema
+     *
+     * @hide
+     */
+    public String getOtaSpNumberSchemaForPhone(int phoneId, String defaultValue) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            return TelephonyManager.getTelephonyProperty(phoneId,
+                    TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA, defaultValue);
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Get SMS receive capable from system property for the default phone.
+     *
+     * @param defaultValue default value
+     * @return SMS receive capable
+     *
+     * @hide
+     */
+    public boolean getSmsReceiveCapable(boolean defaultValue) {
+        int phoneId = getDefaultPhone();
+        return getSmsReceiveCapableForPhone(phoneId, defaultValue);
+    }
+
+    /**
+     * Get SMS receive capable from system property by phone id.
+     *
+     * @param phoneId for which SMS receive capable is get
+     * @param defaultValue default value
+     * @return SMS receive capable
+     *
+     * @hide
+     */
+    public boolean getSmsReceiveCapableForPhone(int phoneId, boolean defaultValue) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            return Boolean.valueOf(TelephonyManager.getTelephonyProperty(phoneId,
+                    TelephonyProperties.PROPERTY_SMS_RECEIVE, String.valueOf(defaultValue)));
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Get SMS send capable from system property for the default phone.
+     *
+     * @param defaultValue default value
+     * @return SMS send capable
+     *
+     * @hide
+     */
+    public boolean getSmsSendCapable(boolean defaultValue) {
+        int phoneId = getDefaultPhone();
+        return getSmsSendCapableForPhone(phoneId, defaultValue);
+    }
+
+    /**
+     * Get SMS send capable from system property by phone id.
+     *
+     * @param phoneId for which SMS send capable is get
+     * @param defaultValue default value
+     * @return SMS send capable
+     *
+     * @hide
+     */
+    public boolean getSmsSendCapableForPhone(int phoneId, boolean defaultValue) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            return Boolean.valueOf(TelephonyManager.getTelephonyProperty(phoneId,
+                    TelephonyProperties.PROPERTY_SMS_SEND, String.valueOf(defaultValue)));
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Set the alphabetic name of current registered operator.
+     * @param name the alphabetic name of current registered operator.
+     * @hide
+     */
+    public void setNetworkOperatorName(String name) {
+        int phoneId = getDefaultPhone();
+        setNetworkOperatorNameForPhone(phoneId, name);
+    }
+
+    /**
+     * Set the alphabetic name of current registered operator.
+     * @param phoneId which phone you want to set
+     * @param name the alphabetic name of current registered operator.
+     * @hide
+     */
+    public void setNetworkOperatorNameForPhone(int phoneId, String name) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, name);
+        }
+    }
+
+    /**
+     * Set the numeric name (MCC+MNC) of current registered operator.
+     * @param operator the numeric name (MCC+MNC) of current registered operator
+     * @hide
+     */
+    public void setNetworkOperatorNumeric(String numeric) {
+        int phoneId = getDefaultPhone();
+        setNetworkOperatorNumericForPhone(phoneId, numeric);
+    }
+
+    /**
+     * Set the numeric name (MCC+MNC) of current registered operator.
+     * @param phoneId for which phone type is set
+     * @param operator the numeric name (MCC+MNC) of current registered operator
+     * @hide
+     */
+    public void setNetworkOperatorNumericForPhone(int phoneId, String numeric) {
+        setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, numeric);
+    }
+
+    /**
+     * Set roaming state of the current network, for GSM purposes.
+     * @param isRoaming is network in romaing state or not
+     * @hide
+     */
+    public void setNetworkRoaming(boolean isRoaming) {
+        int phoneId = getDefaultPhone();
+        setNetworkRoamingForPhone(phoneId, isRoaming);
+    }
+
+    /**
+     * Set roaming state of the current network, for GSM purposes.
+     * @param phoneId which phone you want to set
+     * @param isRoaming is network in romaing state or not
+     * @hide
+     */
+    public void setNetworkRoamingForPhone(int phoneId, boolean isRoaming) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
+                    isRoaming ? "true" : "false");
+        }
+    }
+
+    /**
+     * Set the ISO country code equivalent of the current registered
+     * operator's MCC (Mobile Country Code).
+     * @param iso the ISO country code equivalent of the current registered
+     * @hide
+     */
+    public void setNetworkCountryIso(String iso) {
+        int phoneId = getDefaultPhone();
+        setNetworkCountryIsoForPhone(phoneId, iso);
+    }
+
+    /**
+     * Set the ISO country code equivalent of the current registered
+     * operator's MCC (Mobile Country Code).
+     * @param phoneId which phone you want to set
+     * @param iso the ISO country code equivalent of the current registered
+     * @hide
+     */
+    public void setNetworkCountryIsoForPhone(int phoneId, String iso) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            setTelephonyProperty(phoneId,
+                    TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
+        }
+    }
+
+    /**
+     * Set the network type currently in use on the device for data transmission.
+     * @param type the network type currently in use on the device for data transmission
+     * @hide
+     */
+    public void setDataNetworkType(int type) {
+        int phoneId = getDefaultPhone();
+        setDataNetworkTypeForPhone(phoneId, type);
+    }
+
+    /**
+     * Set the network type currently in use on the device for data transmission.
+     * @param phoneId which phone you want to set
+     * @param type the network type currently in use on the device for data transmission
+     * @hide
+     */
+    public void setDataNetworkTypeForPhone(int phoneId, int type) {
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            setTelephonyProperty(phoneId,
+                    TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
+                    ServiceState.rilRadioTechnologyToString(type));
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index eec5333..c91a59c 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -33,10 +33,10 @@
     String getNaiForSubscriber(int subId);
 
     /**
-     * Retrieves the unique device ID of a subId for the device, e.g., IMEI
+     * Retrieves the unique device ID of a phone for the device, e.g., IMEI
      * for GSM phones.
      */
-    String getDeviceIdForSubscriber(int subId);
+    String getDeviceIdForPhone(int phoneId);
 
     /**
      * Retrieves the IMEI.
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 6fdf121..70ac268 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -453,10 +453,6 @@
      */
     void setPremiumSmsPermission(String packageName, int permission);
 
-    /**
-     * Set the SMS send permission for the specified package.
-     * Requires system permission.
-     */
      /**
      * Set the SMS send permission for the specified package.
      * Requires system permission.
@@ -483,6 +479,14 @@
      */
     boolean isImsSmsSupportedForSubscriber(int subId);
 
+    /**
+     * User needs to pick SIM for SMS if multiple SIMs present and if current subId passed in is not
+     * active/valid.
+     * @param subId current subId for sending SMS
+     * @return true if SIM for SMS sending needs to be chosen
+     */
+    boolean isSmsSimPickActivityNeeded(int subId);
+
     /*
      * get user prefered SMS subId
      * @return subId id
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 2d35129..871e04f 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -345,7 +345,8 @@
 
         return ++currentIndex;
     } else {
-        if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
+        if ((part.length() == 2 || part.length() == 3)
+               && isAlpha(part) && strcmp("car", part.string())) {
             setLanguage(part);
             if (++currentIndex == size) {
                 return size;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f4581d0..8a0a39c 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2531,22 +2531,17 @@
 
 int runInDaemonMode(Bundle* bundle) {
     std::cout << "Ready" << std::endl;
-    for (std::string line; std::getline(std::cin, line);) {
-        if (line == "quit") {
+    for (std::string cmd; std::getline(std::cin, cmd);) {
+        if (cmd == "quit") {
             return NO_ERROR;
-        }
-        std::stringstream ss;
-        ss << line;
-        std::string s;
-
-        std::string command, parameterOne, parameterTwo;
-        std::getline(ss, command, ' ');
-        std::getline(ss, parameterOne, ' ');
-        std::getline(ss, parameterTwo, ' ');
-        if (command[0] == 's') {
-            bundle->setSingleCrunchInputFile(parameterOne.c_str());
-            bundle->setSingleCrunchOutputFile(parameterTwo.c_str());
-            std::cout << "Crunching " << parameterOne << std::endl;
+        } else if (cmd == "s") {
+            // Two argument crunch
+            std::string inputFile, outputFile;
+            std::getline(std::cin, inputFile);
+            std::getline(std::cin, outputFile);
+            bundle->setSingleCrunchInputFile(inputFile.c_str());
+            bundle->setSingleCrunchOutputFile(outputFile.c_str());
+            std::cout << "Crunching " << inputFile << std::endl;
             if (doSingleCrunch(bundle) != NO_ERROR) {
                 std::cout << "Error" << std::endl;
             }
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index e795d818..ef3860c 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -76,3 +76,9 @@
     EXPECT_TRUE(TestParse("sw600dp-v8", &config));
     EXPECT_EQ(String8("sw600dp-v13"), config.toString());
 }
+
+TEST(AaptConfigTest, TestParsingOfCarAttribute) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("car", &config));
+    EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index a2bd6d7..18036927 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -614,15 +614,27 @@
 
             int pos = value.indexOf('/');
             String idName = value.substring(pos + 1);
+            boolean create = value.startsWith("@+");
+            boolean isFrameworkId =
+                    mPlatformFile || value.startsWith("@android") || value.startsWith("@+android");
 
-            // if this is a framework id
-            if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
-                // look for idName in the android R classes
-                return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
+            // Look for the idName in project or android R class depending on isPlatform.
+            if (create) {
+                Integer idValue;
+                if (isFrameworkId) {
+                    idValue = Bridge.getResourceId(ResourceType.ID, idName);
+                } else {
+                    idValue = mContext.getProjectCallback().getResourceId(ResourceType.ID, idName);
+                }
+                return idValue == null ? defValue : idValue;
             }
-
-            // look for idName in the project R class.
-            return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
+            // This calls the same method as in if(create), but doesn't create a dynamic id, if
+            // one is not found.
+            if (isFrameworkId) {
+                return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
+            } else {
+                return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
+            }
         }
 
         // not a direct id valid reference? resolve it
diff --git a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 0100dc5..0000000
--- a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.RenderAction;
-
-import android.content.Context;
-import android.view.BridgeInflater;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * Custom implementation of PolicyManager that does nothing to run in LayoutLib.
- *
- */
-public class PolicyManager {
-
-    public static Window makeNewWindow(Context context) {
-        // this will likely crash somewhere beyond so we log it.
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Call to PolicyManager.makeNewWindow is not supported", null);
-        return null;
-    }
-
-    public static LayoutInflater makeNewLayoutInflater(Context context) {
-        return new BridgeInflater(context, RenderAction.getCurrentContext().getProjectCallback());
-    }
-
-    public static WindowManagerPolicy makeNewWindowManager() {
-        // this will likely crash somewhere beyond so we log it.
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Call to PolicyManager.makeNewWindowManager is not supported", null);
-        return null;
-    }
-
-    public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
-        return new FallbackEventHandler() {
-            @Override
-            public void setView(View v) {
-            }
-
-            @Override
-            public void preDispatchKeyEvent(KeyEvent event) {
-            }
-
-            @Override
-            public boolean dispatchKeyEvent(KeyEvent event) {
-                return false;
-            }
-        };
-    }
-}
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 3953624..3441878 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
@@ -289,6 +289,11 @@
             value = mRenderResources.resolveResValue(value);
         }
 
+        if (value == null) {
+            // unable to find the attribute.
+            return false;
+        }
+
         // check if this is a style resource
         if (value instanceof StyleResourceValue) {
             // get the id that will represent this style.
@@ -296,7 +301,6 @@
             return true;
         }
 
-
         int a;
         // if this is a framework value.
         if (value.isFramework()) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
new file mode 100644
index 0000000..e5023b8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -0,0 +1,166 @@
+/*
+ * 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.layoutlib.bridge.bars;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.ResourceType;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+/**
+ * Assumes that the AppCompat library is present in the project's classpath and creates an
+ * actionbar around it.
+ */
+public class AppCompatActionBar extends BridgeActionBar {
+
+    private Object mWindowDecorActionBar;
+    private static final String WINDOW_ACTION_BAR_CLASS = "android.support.v7.internal.app.WindowDecorActionBar";
+    private Class<?> mWindowActionBarClass;
+
+    /**
+     * Inflate the action bar and attach it to {@code parentView}
+     */
+    public AppCompatActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
+            @NonNull ViewGroup parentView) {
+        super(context, params, parentView);
+        int contentRootId = context.getProjectResourceValue(ResourceType.ID,
+                "action_bar_activity_content", 0);
+        View contentView = getDecorContent().findViewById(contentRootId);
+        if (contentView != null) {
+            assert contentView instanceof FrameLayout;
+            setContentRoot(((FrameLayout) contentView));
+        } else {
+            // Something went wrong. Create a new FrameLayout in the enclosing layout.
+            FrameLayout contentRoot = new FrameLayout(context);
+            setMatchParent(contentRoot);
+            mEnclosingLayout.addView(contentRoot);
+            setContentRoot(contentRoot);
+        }
+        try {
+            Class[] constructorParams = {View.class};
+            Object[] constructorArgs = {getDecorContent()};
+            mWindowDecorActionBar = params.getProjectCallback().loadView(WINDOW_ACTION_BAR_CLASS,
+                    constructorParams, constructorArgs);
+
+            mWindowActionBarClass = mWindowDecorActionBar == null ? null :
+                    mWindowDecorActionBar.getClass();
+            setupActionBar();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    protected ResourceValue getLayoutResource(BridgeContext context) {
+        // We always assume that the app has requested the action bar.
+        return context.getRenderResources().getProjectResource(ResourceType.LAYOUT,
+                "abc_screen_toolbar");
+    }
+
+    @Override
+    protected void setTitle(CharSequence title) {
+        if (title != null && mWindowDecorActionBar != null) {
+            Method setTitle = getMethod(mWindowActionBarClass, "setTitle", CharSequence.class);
+            invoke(setTitle, mWindowDecorActionBar, title);
+        }
+    }
+
+    @Override
+    protected void setSubtitle(CharSequence subtitle) {
+        if (subtitle != null && mWindowDecorActionBar != null) {
+            Method setSubtitle = getMethod(mWindowActionBarClass, "setSubtitle", CharSequence.class);
+            invoke(setSubtitle, mWindowDecorActionBar, subtitle);
+        }
+    }
+
+    @Override
+    protected void setIcon(String icon) {
+        // Do this only if the action bar doesn't already have an icon.
+        if (icon != null && !icon.isEmpty() && mWindowDecorActionBar != null) {
+            if (((Boolean) invoke(getMethod(mWindowActionBarClass, "hasIcon"), mWindowDecorActionBar)
+            )) {
+                Drawable iconDrawable = getDrawable(icon, false);
+                if (iconDrawable != null) {
+                    Method setIcon = getMethod(mWindowActionBarClass, "setIcon", Drawable.class);
+                    invoke(setIcon, mWindowDecorActionBar, iconDrawable);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void setHomeAsUp(boolean homeAsUp) {
+        if (mWindowDecorActionBar != null) {
+            Method setHomeAsUp = getMethod(mWindowActionBarClass,
+                    "setDefaultDisplayHomeAsUpEnabled", boolean.class);
+            invoke(setHomeAsUp, mWindowDecorActionBar, homeAsUp);
+        }
+    }
+
+    @Override
+    public void createMenuPopup() {
+        // it's hard to addd menus to appcompat's actionbar, since it'll use a lot of reflection.
+        // so we skip it for now.
+    }
+
+    @Nullable
+    private static Method getMethod(Class<?> owner, String name, Class<?>... parameterTypes) {
+        try {
+            return owner == null ? null : owner.getMethod(name, parameterTypes);
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Nullable
+    private static Object invoke(Method method, Object owner, Object... args) {
+        try {
+            return method == null ? null : method.invoke(owner, args);
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    // TODO: this is duplicated from FrameworkActionBarWrapper$WindowActionBarWrapper
+    @Nullable
+    private Drawable getDrawable(@NonNull String name, boolean isFramework) {
+        RenderResources res = mBridgeContext.getRenderResources();
+        ResourceValue value = res.findResValue(name, isFramework);
+        value = res.resolveResValue(value);
+        if (value != null) {
+            return ResourceHelper.getDrawable(value, mBridgeContext);
+        }
+        return null;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
new file mode 100644
index 0000000..b29d25f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
@@ -0,0 +1,159 @@
+/*
+ * 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.layoutlib.bridge.bars;
+
+import com.android.annotations.NonNull;
+import com.android.ide.common.rendering.api.ActionBarCallback;
+import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+/**
+ * An abstraction over two implementations of the ActionBar - framework and appcompat.
+ */
+public abstract class BridgeActionBar {
+    // Store a reference to the context so that we don't have to cast it repeatedly.
+    @NonNull protected final BridgeContext mBridgeContext;
+    @NonNull protected final SessionParams mParams;
+    // A Layout that contains the inflated action bar. The menu popup is added to this layout.
+    @NonNull protected final ViewGroup mEnclosingLayout;
+
+    private final View mDecorContent;
+    private final ActionBarCallback mCallback;
+
+    @NonNull private FrameLayout mContentRoot;
+
+    public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
+            @NonNull ViewGroup parentView) {
+        mBridgeContext = context;
+        mParams = params;
+        mCallback = params.getProjectCallback().getActionBarCallback();
+        ResourceValue layoutName = getLayoutResource(context);
+        if (layoutName == null) {
+            throw new RuntimeException("Unable to find the layout for Action Bar.");
+        }
+        int layoutId;
+        if (layoutName.isFramework()) {
+            layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
+                    layoutName.getName(), 0);
+        } else {
+            layoutId = context.getProjectResourceValue(layoutName.getResourceType(),
+                    layoutName.getName(), 0);
+
+        }
+        if (layoutId == 0) {
+            throw new RuntimeException(
+                    String.format("Unable to resolve attribute \"%1$s\" of type \"%2$s\"",
+                            layoutName.getName(), layoutName.getResourceType()));
+        }
+        if (mCallback.isOverflowPopupNeeded()) {
+            // Create a RelativeLayout around the action bar, to which the overflow popup may be
+            // added.
+            mEnclosingLayout = new RelativeLayout(mBridgeContext);
+            setMatchParent(mEnclosingLayout);
+            parentView.addView(mEnclosingLayout);
+        } else {
+            mEnclosingLayout = parentView;
+        }
+
+        // Inflate action bar layout.
+        mDecorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
+
+    }
+
+    /**
+     * Returns the Layout Resource that should be used to inflate the action bar. This layout
+     * should cover the complete screen, and have a FrameLayout included, where the content will
+     * be inflated.
+     */
+    protected abstract ResourceValue getLayoutResource(BridgeContext context);
+
+    protected void setContentRoot(FrameLayout contentRoot) {
+        mContentRoot = contentRoot;
+    }
+
+    @NonNull
+    public FrameLayout getContentRoot() {
+        return mContentRoot;
+    }
+
+    /**
+     * Returns the view inflated. This should contain both the ActionBar and the app content in it.
+     */
+    protected View getDecorContent() {
+        return mDecorContent;
+    }
+
+    /** Setup things like the title, subtitle, icon etc. */
+    protected void setupActionBar() {
+        setTitle();
+        setSutTitle();
+        setIcon();
+        setHomeAsUp(mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP);
+    }
+
+    protected abstract void setTitle(CharSequence title);
+    protected abstract void setSubtitle(CharSequence subtitle);
+    protected abstract void setIcon(String icon);
+    protected abstract void setHomeAsUp(boolean homeAsUp);
+
+    private void setTitle() {
+        RenderResources res = mBridgeContext.getRenderResources();
+
+        String title = mParams.getAppLabel();
+        ResourceValue titleValue = res.findResValue(title, false);
+        if (titleValue != null && titleValue.getValue() != null) {
+            setTitle(titleValue.getValue());
+        } else {
+            setTitle(title);
+        }
+    }
+
+    private void setSutTitle() {
+        String subTitle = mCallback.getSubTitle();
+        if (subTitle != null) {
+            setSubtitle(subTitle);
+        }
+    }
+
+    private void setIcon() {
+        String appIcon = mParams.getAppIcon();
+        if (appIcon != null) {
+            setIcon(appIcon);
+        }
+    }
+
+    public abstract void createMenuPopup();
+
+    public ActionBarCallback getCallBack() {
+        return mCallback;
+    }
+
+    protected static void setMatchParent(View view) {
+        view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
similarity index 76%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
index 2ff8d37..a1c9065 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
@@ -31,7 +31,7 @@
 import android.content.res.TypedArray;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
-import android.view.LayoutInflater;
+import android.view.InflateException;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -44,70 +44,30 @@
 
 import java.util.ArrayList;
 
-public class ActionBarLayout {
+/**
+ * Creates the ActionBar as done by the framework.
+ */
+public class FrameworkActionBar extends BridgeActionBar {
 
     private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout";
 
     // The Action Bar
-    @NonNull
-    private CustomActionBarWrapper mActionBar;
-
-    // Store another reference to the context so that we don't have to cast it repeatedly.
-    @NonNull
-    private final BridgeContext mBridgeContext;
-
-    @NonNull
-    private FrameLayout mContentRoot;
+    @NonNull private FrameworkActionBarWrapper mActionBar;
 
     // A fake parent for measuring views.
-    @Nullable
-    private ViewGroup mMeasureParent;
-
-    // A Layout that contains the inflated action bar. The menu popup is added to this layout.
-    @NonNull
-    private final RelativeLayout mEnclosingLayout;
+    @Nullable private ViewGroup mMeasureParent;
 
     /**
      * Inflate the action bar and attach it to {@code parentView}
      */
-    public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params,
+    public FrameworkActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
             @NonNull ViewGroup parentView) {
+        super(context, params, parentView);
 
-        mBridgeContext = context;
+        View decorContent = getDecorContent();
 
-        ResourceValue layoutName = context.getRenderResources()
-                .findItemInTheme(LAYOUT_ATTR_NAME, true);
-        if (layoutName != null) {
-            // We may need to resolve the reference obtained.
-            layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
-                    layoutName.isFramework());
-        }
-        int layoutId = 0;
-        String error = null;
-        if (layoutName == null) {
-            error = "Unable to find action bar layout (" + LAYOUT_ATTR_NAME
-                    + ") in the current theme.";
-        } else {
-            layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
-                    layoutName.getName(), 0);
-            if (layoutId == 0) {
-                error = String.format("Unable to resolve attribute \"%s\" of type \"%s\"",
-                        layoutName.getName(), layoutName.getResourceType());
-            }
-        }
-        if (layoutId == 0) {
-            throw new RuntimeException(error);
-        }
-        // Create a RelativeLayout to hold the action bar. The layout is needed so that we may
-        // add the menu popup to it.
-        mEnclosingLayout = new RelativeLayout(mBridgeContext);
-        setMatchParent(mEnclosingLayout);
-        parentView.addView(mEnclosingLayout);
-
-        // Inflate action bar layout.
-        View decorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
-
-        mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent);
+        mActionBar = FrameworkActionBarWrapper.getActionBarWrapper(context, getCallBack(),
+                decorContent);
 
         FrameLayout contentRoot = (FrameLayout) mEnclosingLayout.findViewById(android.R.id.content);
 
@@ -117,27 +77,62 @@
             contentRoot = new FrameLayout(context);
             setMatchParent(contentRoot);
             mEnclosingLayout.addView(contentRoot);
-            mContentRoot = contentRoot;
+            setContentRoot(contentRoot);
         } else {
-            mContentRoot = contentRoot;
-            mActionBar.setupActionBar();
+            setContentRoot(contentRoot);
+            setupActionBar();
             mActionBar.inflateMenus();
         }
     }
 
-    private void setMatchParent(View view) {
-        view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
+    @Override
+    protected ResourceValue getLayoutResource(BridgeContext context) {
+        ResourceValue layoutName =
+                context.getRenderResources().findItemInTheme(LAYOUT_ATTR_NAME, true);
+        if (layoutName != null) {
+            // We may need to resolve the reference obtained.
+            layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
+                    layoutName.isFramework());
+        }
+        if (layoutName == null) {
+             throw new InflateException("Unable to find action bar layout (" + LAYOUT_ATTR_NAME
+                    + ") in the current theme.");
+        }
+        return layoutName;
+    }
+
+    @Override
+    protected void setupActionBar() {
+        super.setupActionBar();
+        mActionBar.setupActionBar();
+    }
+
+    @Override
+    protected void setHomeAsUp(boolean homeAsUp) {
+        mActionBar.setHomeAsUp(homeAsUp);
+    }
+
+    @Override
+    protected void setTitle(CharSequence title) {
+        mActionBar.setTitle(title);
+    }
+
+    @Override
+    protected void setSubtitle(CharSequence subtitle) {
+        mActionBar.setSubTitle(subtitle);
+    }
+
+    @Override
+    protected void setIcon(String icon) {
+        mActionBar.setIcon(icon);
     }
 
     /**
      * Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to
      * the content frame which shall serve as the new content root.
      */
+    @Override
     public void createMenuPopup() {
-        assert mEnclosingLayout.getChildCount() == 1
-                : "Action Bar Menus have already been created.";
-
         if (!isOverflowPopupNeeded()) {
             return;
         }
@@ -193,11 +188,6 @@
         return needed;
     }
 
-    @NonNull
-    public FrameLayout getContentRoot() {
-        return mContentRoot;
-    }
-
     // Copied from com.android.internal.view.menu.MenuPopHelper.measureContentWidth()
     private int measureContentWidth(@NonNull ListAdapter adapter) {
         // Menus don't tend to be long, so this is more sane than it looks.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
similarity index 81%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
index 6db722e..44c2cd8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
@@ -19,10 +19,8 @@
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
 import com.android.ide.common.rendering.api.ActionBarCallback;
-import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.SessionParams;
 import com.android.internal.R;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
@@ -54,10 +52,9 @@
 /**
  * A common API to access {@link ToolbarActionBar} and {@link WindowDecorActionBar}.
  */
-public abstract class CustomActionBarWrapper {
+public abstract class FrameworkActionBarWrapper {
 
     @NonNull protected ActionBar mActionBar;
-    @NonNull protected SessionParams mParams;
     @NonNull protected ActionBarCallback mCallback;
     @NonNull protected BridgeContext mContext;
 
@@ -68,49 +65,48 @@
      *                     ?attr/windowActionBarFullscreenDecorLayout
      */
     @NonNull
-    public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
-            @NonNull SessionParams params, @NonNull View decorContent) {
+    public static FrameworkActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
+            @NonNull ActionBarCallback callback, @NonNull View decorContent) {
         View view = decorContent.findViewById(R.id.action_bar);
         if (view instanceof Toolbar) {
-            return new ToolbarWrapper(context, params, ((Toolbar) view));
+            return new ToolbarWrapper(context, callback, (Toolbar) view);
         } else if (view instanceof ActionBarView) {
-            return new WindowActionBarWrapper(context, params, decorContent,
-                    ((ActionBarView) view));
+            return new WindowActionBarWrapper(context, callback, decorContent,
+                    (ActionBarView) view);
         } else {
             throw new IllegalStateException("Can't make an action bar out of " +
                     view.getClass().getSimpleName());
         }
     }
 
-    CustomActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+    FrameworkActionBarWrapper(@NonNull BridgeContext context, ActionBarCallback callback,
             @NonNull ActionBar actionBar) {
         mActionBar = actionBar;
-        mParams = params;
-        mCallback = params.getProjectCallback().getActionBarCallback();
+        mCallback = callback;
         mContext = context;
     }
 
+    /** A call to setup any custom properties. */
     protected void setupActionBar() {
-        // Do the things that are common to all implementations.
-        RenderResources res = mContext.getRenderResources();
+        // Nothing to do here.
+    }
 
-        String title = mParams.getAppLabel();
-        ResourceValue titleValue = res.findResValue(title, false);
-        if (titleValue != null && titleValue.getValue() != null) {
-            mActionBar.setTitle(titleValue.getValue());
-        } else {
-            mActionBar.setTitle(title);
-        }
+    public void setTitle(CharSequence title) {
+        mActionBar.setTitle(title);
+    }
 
-        String subTitle = mCallback.getSubTitle();
+    public void setSubTitle(CharSequence subTitle) {
         if (subTitle != null) {
             mActionBar.setSubtitle(subTitle);
         }
+    }
 
-        // Add show home as up icon.
-        if (mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP) {
-            mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
-        }
+    public void setHomeAsUp(boolean homeAsUp) {
+        mActionBar.setDisplayHomeAsUpEnabled(homeAsUp);
+    }
+
+    public void setIcon(String icon) {
+        // Nothing to do.
     }
 
     protected boolean isSplit() {
@@ -186,15 +182,14 @@
      * Material theme uses {@link Toolbar} as the action bar. This wrapper provides access to
      * Toolbar using a common API.
      */
-    private static class ToolbarWrapper extends CustomActionBarWrapper {
+    private static class ToolbarWrapper extends FrameworkActionBarWrapper {
 
         @NonNull
         private final Toolbar mToolbar;  // This is the view.
 
-        ToolbarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+        ToolbarWrapper(@NonNull BridgeContext context, @NonNull ActionBarCallback callback,
                 @NonNull Toolbar toolbar) {
-            super(context, params, new ToolbarActionBar(toolbar, "", new WindowCallback())
-            );
+            super(context, callback, new ToolbarActionBar(toolbar, "", new WindowCallback()));
             mToolbar = toolbar;
         }
 
@@ -248,19 +243,17 @@
      * Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides
      * access to it using a common API.
      */
-    private static class WindowActionBarWrapper extends CustomActionBarWrapper {
+    private static class WindowActionBarWrapper extends FrameworkActionBarWrapper {
 
-        @NonNull
-        private final WindowDecorActionBar mActionBar;
-        @NonNull
-        private final ActionBarView mActionBarView;
-        @NonNull
-        private final View mDecorContentRoot;
+        @NonNull private final WindowDecorActionBar mActionBar;
+        @NonNull private final ActionBarView mActionBarView;
+        @NonNull private final View mDecorContentRoot;
         private MenuBuilder mMenuBuilder;
 
-        public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
-                @NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) {
-            super(context, params, new WindowDecorActionBar(decorContentRoot));
+        public WindowActionBarWrapper(@NonNull BridgeContext context,
+                @NonNull ActionBarCallback callback, @NonNull View decorContentRoot,
+                @NonNull ActionBarView actionBarView) {
+            super(context, callback, new WindowDecorActionBar(decorContentRoot));
             mActionBarView = actionBarView;
             mActionBar = ((WindowDecorActionBar) super.mActionBar);
             mDecorContentRoot = decorContentRoot;
@@ -268,7 +261,6 @@
 
         @Override
         protected void setupActionBar() {
-            super.setupActionBar();
 
             // Set the navigation mode.
             int navMode = mCallback.getNavigationMode();
@@ -278,16 +270,6 @@
                 setupTabs(3);
             }
 
-            String icon = mParams.getAppIcon();
-            // If the action bar style doesn't specify an icon, set the icon obtained from the
-            // session params.
-            if (!mActionBar.hasIcon() && icon != null) {
-                Drawable iconDrawable = getDrawable(icon, false);
-                if (iconDrawable != null) {
-                    mActionBar.setIcon(iconDrawable);
-                }
-            }
-
             // Set action bar to be split, if needed.
             ViewGroup splitView = (ViewGroup) mDecorContentRoot.findViewById(R.id.split_action_bar);
             if (splitView != null) {
@@ -300,6 +282,17 @@
         }
 
         @Override
+        public void setIcon(String icon) {
+            // Set the icon only if the action bar doesn't specify an icon.
+            if (!mActionBar.hasIcon() && icon != null) {
+                Drawable iconDrawable = getDrawable(icon, false);
+                if (iconDrawable != null) {
+                    mActionBar.setIcon(iconDrawable);
+                }
+            }
+        }
+
+        @Override
         protected void inflateMenus() {
             super.inflateMenus();
             // The super implementation doesn't set the menu on the view. Set it here.
@@ -340,7 +333,7 @@
 
         @Override
         int getMenuPopupMargin() {
-            return -ActionBarLayout.getPixelValue("10dp", mContext.getMetrics());
+            return -FrameworkActionBar.getPixelValue("10dp", mContext.getMetrics());
         }
 
         // TODO: Use an adapter, like List View to set up tabs.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index fd976af..84ee914 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -51,11 +51,13 @@
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
 import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.bars.BridgeActionBar;
+import com.android.layoutlib.bridge.bars.AppCompatActionBar;
 import com.android.layoutlib.bridge.bars.Config;
 import com.android.layoutlib.bridge.bars.NavigationBar;
 import com.android.layoutlib.bridge.bars.StatusBar;
 import com.android.layoutlib.bridge.bars.TitleBar;
-import com.android.layoutlib.bridge.bars.ActionBarLayout;
+import com.android.layoutlib.bridge.bars.FrameworkActionBar;
 import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
 import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
 import com.android.resources.Density;
@@ -354,7 +356,7 @@
 
                 // if the theme says no title/action bar, then the size will be 0
                 if (mActionBarSize > 0) {
-                    ActionBarLayout actionBar = createActionBar(context, params, backgroundLayout);
+                    BridgeActionBar actionBar = createActionBar(context, params, backgroundLayout);
                     actionBar.createMenuPopup();
                     mContentRoot = actionBar.getContentRoot();
                 } else if (mTitleBarSize > 0) {
@@ -1190,8 +1192,22 @@
         // android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
         if (mIsThemeAppCompat == null) {
             StyleResourceValue defaultTheme = resources.getDefaultTheme();
-            StyleResourceValue val = resources.getStyle("Theme.AppCompat", false);
-            mIsThemeAppCompat = defaultTheme == val || resources.themeIsParentOf(val, defaultTheme);
+          // We can't simply check for parent using resources.themeIsParentOf() since the
+          // inheritance structure isn't really what one would expect. The first common parent
+          // between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
+            boolean isThemeAppCompat = false;
+            for (int i = 0; i < 50; i++) {
+                // for loop ensures that we don't run into cyclic theme inheritance.
+                if (defaultTheme.getName().startsWith("Theme.AppCompat")) {
+                    isThemeAppCompat = true;
+                    break;
+                }
+                defaultTheme = resources.getParent(defaultTheme);
+                if (defaultTheme == null) {
+                    break;
+                }
+            }
+            mIsThemeAppCompat = isThemeAppCompat;
         }
         return mIsThemeAppCompat;
     }
@@ -1647,9 +1663,13 @@
     /**
      * Creates the action bar. Also queries the project callback for missing information.
      */
-    private ActionBarLayout createActionBar(BridgeContext context, SessionParams params,
+    private BridgeActionBar createActionBar(BridgeContext context, SessionParams params,
             ViewGroup parentView) {
-        return new ActionBarLayout(context, params, parentView);
+        if (mIsThemeAppCompat == Boolean.TRUE) {
+            return new AppCompatActionBar(context, params, parentView);
+        } else {
+            return new FrameworkActionBar(context, params, parentView);
+        }
     }
 
     public BufferedImage getImage() {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 8f50c5d..f5e8292 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -254,7 +254,6 @@
             "android.view.SurfaceView",                        "android.view._Original_SurfaceView",
             "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
             "android.webkit.WebView",                          "android.webkit._Original_WebView",
-            "com.android.internal.policy.PolicyManager",       "com.android.internal.policy._Original_PolicyManager",
         };
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5202cc3..52f2372 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -733,6 +733,31 @@
 
     /**
      * @hide
+     * Last time the system tried to roam and failed because of authentication failure or DHCP
+     * RENEW failure.
+     */
+    public long lastRoamingFailure;
+
+    /** @hide */
+    public static int ROAMING_FAILURE_IP_CONFIG = 1;
+    /** @hide */
+    public static int ROAMING_FAILURE_AUTH_FAILURE = 2;
+
+    /**
+     * @hide
+     * Initial amount of time this Wifi configuration gets blacklisted for network switching
+     * because of roaming failure
+     */
+    public long roamingFailureBlackListTimeMilli = 1000;
+
+    /**
+     * @hide
+     * Last roaming failure reason code
+     */
+    public int lastRoamingFailureReason;
+
+    /**
+     * @hide
      * Last time the system was disconnected to this configuration.
      */
     public long lastDisconnected;
@@ -1209,6 +1234,18 @@
                 sbuf.append( "sec");
             }
         }
+        if (this.lastRoamingFailure != 0) {
+            sbuf.append('\n');
+            long diff = now_ms - this.lastRoamingFailure;
+            if (diff <= 0) {
+                sbuf.append("lastRoamingFailure since <incorrect>");
+            } else {
+                sbuf.append("lastRoamingFailure: ").append(Long.toString(diff/1000));
+                sbuf.append( "sec");
+            }
+        }
+        sbuf.append("roamingFailureBlackListTimeMilli: ").
+                append(Long.toString(this.roamingFailureBlackListTimeMilli));
         sbuf.append('\n');
         if (this.linkedConfigurations != null) {
             for(String key : this.linkedConfigurations.keySet()) {
@@ -1595,6 +1632,9 @@
             lastConnected = source.lastConnected;
             lastDisconnected = source.lastDisconnected;
             lastConnectionFailure = source.lastConnectionFailure;
+            lastRoamingFailure = source.lastRoamingFailure;
+            lastRoamingFailureReason = source.lastRoamingFailureReason;
+            roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
             numConnectionFailures = source.numConnectionFailures;
             numIpConfigFailures = source.numIpConfigFailures;
             numAuthFailures = source.numAuthFailures;
@@ -1667,6 +1707,9 @@
         dest.writeString(lastUpdateName);
         dest.writeLong(blackListTimestamp);
         dest.writeLong(lastConnectionFailure);
+        dest.writeLong(lastRoamingFailure);
+        dest.writeInt(lastRoamingFailureReason);
+        dest.writeLong(roamingFailureBlackListTimeMilli);
         dest.writeInt(numConnectionFailures);
         dest.writeInt(numIpConfigFailures);
         dest.writeInt(numAuthFailures);
@@ -1732,6 +1775,9 @@
                 config.lastUpdateName = in.readString();
                 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();